bzoj3624(铺黑白路)(并查集维护)
题意网上自己随便找,绝对是找的到的。
题解:(白边表示鹅卵石路,黑边表示水泥路)这道题的解法,先考虑将黑边所有都先连起来,组成一个又一个的联通块,然后用白边去连,
如果可以联通的话,就用白边去代替黑边,必要的白边(就是维护联通性的白边必须要先保证),然后再去代替,直到k条边满足,不满足则输出NO
然后就再用黑边去连,记录,反正是Special Judge所以顺序没有关系,就好了。
1 #include<cmath> 2 #include<cstdio> 3 #include<cstring> 4 #include<iostream> 5 #include<algorithm> 6 using namespace std; 7 8 typedef long long ll; 9 const int INF=1e9+7,NN=20007,MM=100007; 10 11 int n,m,K,top; 12 int fa[NN]; 13 int u[MM],v[MM],c[MM]; 14 int au[NN],av[NN],ac[NN]; 15 bool mark[MM]; 16 int num[2]; 17 18 int find(int num) 19 { 20 if (fa[num]==num) return num; 21 else fa[num]=find(fa[num]); 22 return fa[num]; 23 } 24 void solve(bool typ,int up) 25 { 26 for(int i=1;i<=m;i++) 27 if(c[i]==typ&&num[typ]<up) 28 { 29 int p=find(u[i]),q=find(v[i]); 30 if(p!=q) 31 { 32 fa[p]=q; 33 au[++top]=u[i],av[top]=v[i],ac[top]=c[i]; 34 mark[i]=1; 35 num[typ]++; 36 } 37 } 38 } 39 void init() 40 { 41 memset(mark,0,sizeof(mark)); 42 scanf("%d%d%d",&n,&m,&K); 43 for(int i=1;i<=m;i++) 44 scanf("%d%d%d",&u[i],&v[i],&c[i]); 45 for(int i=1;i<=n;i++) 46 fa[i]=i; 47 } 48 int main() 49 { 50 init(); 51 52 num[0]=num[1]=0; 53 solve(1,INF),solve(0,INF); 54 if(num[1]+num[0]!=n-1||num[0]>K) 55 { 56 puts("no solution\n"); 57 return 0; 58 }//及如果需要>k条鹅卵石路将各个块连起来,或者需要多余n-1条边 59 60 top=num[0]=num[1]=0;//然后用鹅卵石重新铺 61 for(int i=1;i<=n;i++) 62 fa[i]=i; 63 for(int i=1;i<=m;i++) 64 if(c[i]==0&&mark[i]) 65 { 66 int p=find(u[i]),q=find(v[i]); 67 if(p!=q) 68 { 69 num[0]++;fa[p]=q; 70 au[++top]=u[i];av[top]=v[i];ac[top]=c[i]; 71 } 72 }//必要的先铺满 73 solve(0,K),solve(1,INF);//然后再不必要鹅卵石的取铺,然后再用水泥路取铺就可以了。 74 if(num[0]<K) 75 { 76 puts("no solution"); 77 return 0; 78 } 79 for(int i=1;i<=top;i++) 80 printf("%d %d %d\n",au[i],av[i],ac[i]); 81 }