码迷,mamicode.com
首页 > 其他好文 > 详细

17.11.08

时间:2017-11-09 22:33:37      阅读:166      评论:0      收藏:0      [点我收藏+]

标签:贪心   问题   font   代码   int   struct   turn   集合   return   

  • 上午 模拟考试
    • 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\n");
      	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\n%I64d\n",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;
      }

17.11.08

标签:贪心   问题   font   代码   int   struct   turn   集合   return   

原文地址:http://www.cnblogs.com/zj75211/p/7811432.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!