zoukankan      html  css  js  c++  java
  • 题解[CF1054G New Road Network]

    题意描述

    Link

    (kals)已经翻得很好了~~

    Sol

    (S_a)(a)点所在集合的集合,(S_b)(b)点所在集合的集合,每次连边((a,b)) ,边权为(S_a)(S_b)的大小,这样建出一张完全图来,跑最大生成树((why?)感性理解:如果我连交集最多、最有可能的、最有希望的连边方式都不可行,那就没有可行的了)。做法看似简单,证明太难 ,实现上有一些难点(如(bitset)),解释一下。

    输入

    for(int i=1;i<=m;i++){
    	char c[N];
    	scanf("%s",c+1);
    	for(int j=1;j<=n;j++)
    		a[j][i]=c[j]-'0',sum[i]+=a[j][i];
    }
    

    (a[j][i])表示第(j)个点是否存在于第(i)个集合里,(sum[i])表示集合(i)里有几个点。

    连边

    for(int i=1;i<n;i++)
    	for(int j=i+1;j<=n;j++)
    		e[++cnt].st=i,e[cnt].ed=j,e[cnt].v=(int)(a[i]&a[j]).count();
    

    (a[i]) & (a[j])表示((i)所在的集合的集合)与((j)所在的集合的集合)的交集,(.count()) 表示交集中(1)的个数,也就是大小。

    判定

    for(int i=1;i<=m;i++){
    	int s=0;
    	for(int j=1;j<n;j++) s+=(a[ans[j].st][i]&&a[ans[j].ed][i]);
      //ans[j].st和ans[j].ed同在集合i里
      //s为集合中边的数量
      //s=点的数量-1
    	if(s!=sum[i]-1){
    		flag=0;
    		break;
    	}
      //不符合输入,构造不出来
    }
    

    Code

    #include<bits/stdc++.h>
    #define M (4000010)
    #define N (2010)
    using namespace std;
    struct xbk{int st,ed,v;}e[M],ans[N];
    int n,m,T,sum[N],fa[N];
    bitset<N>a[N];
    inline int read(){
    	int w=0;
    	char ch=getchar();
    	while(ch>'9'||ch<'0') ch=getchar();
    	while(ch>='0'&&ch<='9'){
    		w=(w<<3)+(w<<1)+(ch^48);
    		ch=getchar();
    	}
    	return w;
    }
    inline bool cmp(xbk a,xbk b){return a.v>b.v;}
    inline int mfind(int x){
    	if(fa[x]!=x) return fa[x]=mfind(fa[x]);
    	return fa[x];
    }
    int main(){
    	T=read();
    	while(T--){
    		n=read(),m=read();
    		int cnt=0,tot=0;
    		memset(sum,0,sizeof(sum));
    		for(int i=1;i<=n;i++) a[i].reset(),fa[i]=i;
    		for(int i=1;i<=m;i++){
    			char c[N];
    			scanf("%s",c+1);
    			for(int j=1;j<=n;j++)
    				a[j][i]=c[j]-'0',sum[i]+=a[j][i];
    		}
    		for(int i=1;i<n;i++)
    			for(int j=i+1;j<=n;j++)
    				e[++cnt].st=i,e[cnt].ed=j,e[cnt].v=(int)(a[i]&a[j]).count();
    		sort(e+1,e+1+cnt,cmp);
    		for(int i=1;i<=cnt;i++){
    			int x=mfind(e[i].st),y=mfind(e[i].ed);
    			if(x==y) continue;
    			fa[x]=y;
    			ans[++tot].st=e[i].st,ans[tot].ed=e[i].ed;
    			if(tot==n-1) break;
    		}
    		bool flag=1;
    		for(int i=1;i<=m;i++){
    			int s=0;
    			for(int j=1;j<n;j++) s+=(a[ans[j].st][i]&&a[ans[j].ed][i]);
    			if(s!=sum[i]-1){
    				flag=0;
    				break;
    			}
    		}
    		if(!flag) puts("NO");
    		else{
    			puts("YES");
    			for(int i=1;i<n;i++) printf("%d %d
    ",ans[i].st,ans[i].ed);
    		}
    	}
    	return 0;
    }
    

    完结撒花❀

  • 相关阅读:
    wpf如何将图片设置为窗体的背景
    C#用Oracle.DataAccess中连接Oracle要注意版本问题!
    C#格式化数值结果表
    将字符串的16进制转换成byte[]
    Java各个类型与byte[]的转换
    记录下 Jquery的使用
    页面div与顶部有缝隙问题
    Js 转换Json返回的时间格式(转)
    Div垂直居中水平居中
    C# 日期格式大全
  • 原文地址:https://www.cnblogs.com/xxbbkk/p/14432465.html
Copyright © 2011-2022 走看看