17.11.08

    • 上午 模拟考试
        • Prob.1(WA30

      模拟,有点小烦。然后double转整型时没有long long,挂了3个点。

      • Prob.2(WA70

简化题目
给出了一个图(n点数<=2500)的两点间的最短距离的邻接矩阵。
问是否存在一颗 n个点的树的邻接矩阵和输入的相同。 (没有负权)

可以发现,如果存在的话,当前邻接表中最小的边一定是树中的一条边。
所以就 最小生成树prim算法,不用优先队列 n^2

然后就是求出当前树的两点间距离的邻接矩阵。比对就好了。
跑n次dfs就出来了 n^2

(智障的我:怎么求树上所有点之间的距离啊,Floyd n^3 要炸啊。简直莫法做,看来只能得30分了)
(、、、、Floyd?!蛤,我在干嘛、、)
代码:

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define ll long long
#define MAXN 2505
#define INF 0x3f3f3f3f
using namespace std;
struct edge{
	ll to,val,next;
}e[MAXN*2];
ll ans[MAXN][2];
ll head[MAXN],fa[MAXN],mp[MAXN][MAXN],dis[MAXN][MAXN];
ll n,ent;
char gc(){
	static char s[100005];
	static int bit=100000,p,len;
	if(p>=len) len=fread(s,1,bit,stdin),s[len]=EOF,p=0;
	return s[p++];
}
void read(ll &x){
	static int f;static char ch;
	x=0; f=1; ch=gc();
	while(ch<'0'||'9'<ch){if(ch=='-')f=-1;ch=gc();}
	while('0'<=ch&&ch<='9'){x=x*10+ch-'0';ch=gc();}
	x=x*f;
}
void add(ll u,ll v,ll w){
	e[ent]=(edge){v,w,head[u]};
	head[u]=ent++;
}
void Prim(){
	static ll d[MAXN],from[MAXN];
	static bool vis[MAXN];
	memset(vis,0,sizeof(vis));
	memset(d,0x3f,sizeof(d));
	memset(head,0,sizeof(head));
	vis[1]=1; ent=2;
	for(ll i=2;i<=n;i++) if(d[i]>mp[1][i]) d[i]=mp[1][i],from[i]=1;
	for(ll k=1,w,v;k<n;k++){
		w=INF;
		for(ll i=1;i<=n;i++) if(!vis[i]&&w>d[i]) w=d[i],v=i;
		add(from[v],v,w); add(v,from[v],w); vis[v]=1;
		ans[from[v]][0]+=w; ans[v][0]+=w; 
		ans[from[v]][1]+=1; ans[v][1]+=1; 
		for(ll i=1;i<=n;i++) if(!vis[i]&&d[i]>mp[v][i]) d[i]=mp[v][i],from[i]=v;
	}
}
void dfs(ll u,ll dad,ll val,ll *DIS){
	DIS[u]=val;
	for(ll i=head[u];i;i=e[i].next){
		ll v=e[i].to;
		if(v==dad) continue;
		dfs(v,u,val+e[i].val,DIS);
	}
}
void check(){
	bool fg=1;
	for(ll i=1;i<=n;i++)
		for(ll j=1;j<=n;j++)
			if(dis[i][j]!=mp[i][j]){fg=0;break;}
	if(!fg) printf("No
");
	else{
		double val=1.0*ans[1][0]/ans[1][1];ll ANS=1;
		for(ll i=2;i<=n;i++) if(1.0*ans[i][0]/ans[i][1]>val) 
			val=1.0*ans[i][0]/ans[i][1],ANS=i;
		printf("Yes
%I64d
",ANS);
	}
}
void work(){
	read(n);
	for(ll i=1;i<=n;i++)
		for(ll j=1;j<=n;j++)
			read(mp[i][j]);
	Prim();
	for(ll i=1;i<=n;i++) dfs(i,0,0,dis[i]);
	check();
}
void init(){
	memset(ans,0,sizeof(ans));
	memset(dis,0,sizeof(dis));
	ent=0;
}
int main(){
	freopen("treas.in","r",stdin);
	freopen("treas.out","w",stdout);
	ll T;
	read(T);
	while(T--){
		init();
		work();
	}
	return 0;
}
      • Prob.3(WA10
      • 一个处理区间覆盖的题。他们都大佬地用O(n)做,我却在弱弱地用线段树维护、、、(就当复习了。)
      • 注意!!!

        1).这种题用到线段树的话,是以单位区间为底层节点的,方便。

        2).离散化后,要在没有紧贴的点中间加入一些 "占位点")
        (要不是数据善良,不然今天就又凉了)

    • 补两个Tyvj上的题,之前忘了记录了。
    • Tyvj P1480 星际大战

状压dp,
dp[S]表示选了"目标"集合为S的元素,这些元素依次被前几个导弹攻击的最小距离和。
然后刷表法,即枚举下一个导弹打哪个目标。
复杂度:2^n*n

代码:

#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std;
const double eps=1e-6;
struct pos{
	int x,y;
}mis[25],aim[25];
double d[25][25],dp[1<<20],hv[1<<20];
int n,all;
int idx(int i){
	return 1<<i;
}
int sign(double x){
	if(fabs(x)<=eps) return 0;
	return x>0?1:-1;
}
void cmin(double &a,double b){
	if(sign(a-b)>0) a=b;
}
double dis(pos a,pos b){
	return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));
}
int main(){
	scanf("%d",&n); all=(1<<n)-1;
	for(int i=0;i<n;i++) scanf("%d%d",&mis[i].x,&mis[i].y);
	for(int i=0;i<n;i++) scanf("%d%d",&aim[i].x,&aim[i].y);
	for(int i=0;i<n;i++) for(int j=0;j<n;j++) d[i][j]=dis(mis[i],aim[j]);
	for(int S=1;S<=all;S++) hv[S]=hv[S>>1]+(S&1),dp[S]=1e9;
	for(int S=0,p;S<all;S++)
		for(int i=0;i<n;i++){
			if(S&idx(i)) continue;
			p=hv[S]; cmin(dp[S|idx(i)],dp[S]+d[p][i]);
		}
	printf("%.3lf",dp[all]);
	return 0;
}
    • Tyvj P4112 删数问题

贪心,依次确定最高位。
显然在可取范围内,最高位越小越好,那么每次就查询可行区间的最小值的位置。
线段树维护(尝试了一下ZKW线段树,感觉很像镜像对称后的树状数组。)
(但是不会区间修改,感觉好麻烦啊,需要区间修改是我还是先直接打线段树吧)

代码:

#include<cstring>
#include<iostream>
#define MAXN 800
using namespace std;
char s[300],ans[300];
struct ZKW{
	int mini[MAXN],pos[MAXN],M,N;
	void update(int &fmini,int &fpos,int smini,int spos){
		if(fmini<smini) return;
		if(fmini==smini&&fpos<spos) return;
		fmini=smini; fpos=spos;
	}
	void build(int n){
		memset(mini,0x3f,sizeof(mini));
		for(M=1;M<=n+1;M<<=1); N=n;
		for(int i=1;i<=n;i++) mini[M+i]=s[i]-'0',pos[M+i]=i;
		for(int i=M;i;i--) 
			update(mini[i],pos[i],mini[i<<1],pos[i<<1]),
			update(mini[i],pos[i],mini[i<<1|1],pos[i<<1|1]);
	}
	int query(int l,int r){
		int v=0x3f3f3f3f,p;
		l=M+l-1;	r=M+r+1;
		for(;l^r^1;l>>=1,r>>=1){
			if(~l&1) update(v,p,mini[l^1],pos[l^1]);
			if(r&1) update(v,p,mini[r^1],pos[r^1]);
		}
		return p;
	}
}T;
int main(){
	int n,m,k,cnt=0,now=0;
	scanf("%s",s+1); n=strlen(s+1);
	T.build(n); int last=0;
	scanf("%d",&m); k=n-m;
	while(k){
		int p=T.query(last+1,last+m+1);
		ans[++cnt]=s[p];
		m-=(p-last-1); k--;
		last=p;
	};
	for(int i=1;i<=cnt;i++) now=now*10+ans[i]-'0';
	printf("%d",now);
	return 0;
}
原文地址:https://www.cnblogs.com/zj75211/p/7811432.html