题解[CF1054G New Road Network]
题意描述
\(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\n",ans[i].st,ans[i].ed);
}
}
return 0;
}