1. 程式人生 > >[luogu]P3623 [APIO2008]免費道路

[luogu]P3623 [APIO2008]免費道路

導致 b- names new pen targe play urn sed

原題鏈接:P3623 [APIO2008]免費道路

題意

給定一個圖(不一定連通),上面有$m$條$0$邊和$1$邊。

要求選邊使圖連通,$0$邊的數量必須等於$k$。

分析

一開始用很天真的想法加邊:先加鵝卵石路,一直加到$k$條。然後再加水泥路,加到滿。

然後發現在洛谷上WA了一個點。

仔細分析一下問題:一對點,如果我們加的是鵝卵石路,那麽我們本可以用水泥路使這一對點連通,我們現在卻使用了一次鵝卵石名額,這樣子可能會導致後面鵝卵石名額不足。

那麽怎麽考慮這個問題呢?

我們發現只有用鵝卵石代替了水泥才會導致名額的沖突,那麽我們只要求出有多少名額是必須給的(不給就不能連通的),然後優先給它們名額。

至於剩下的,就先把鵝卵石的名額加到$k$,然後再加水泥路加到滿就可以了。

代碼

技術分享圖片
 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 const int N=2e5+1000,M=3e5+1000;
 4 struct edge{
 5     int x,y;
 6 }sn[M],er[M];
 7 int read(){
 8     char c;int num,f=1;
 9     while(c=getchar(),!isdigit(c))if(c==-)f=-1;num=c-0;
10 while(c=getchar(), isdigit(c))num=num*10+c-0; 11 return f*num; 12 } 13 int n,m,k,pre[N]; 14 int tot1=0,tot2=0,ans=0; 15 int pt[M][4],vis[M]; 16 int fid(int x){return (x==pre[x])?x:(pre[x]=fid(pre[x]));} 17 int main() 18 { 19 n=read();m=read(); 20 k=read(); 21 for(int i=1
;i<=m;i++){ 22 int u,v,w; 23 u=read();v=read(); 24 w=read(); 25 if(w==1){ 26 sn[++tot1].x=u; 27 sn[ tot1].y=v; 28 }else{ 29 er[++tot2].x=u; 30 er[ tot2].y=v; 31 } 32 } 33 if(tot2<k)goto no; 34 int tt=0; 35 for(int i=1;i<=n;i++)pre[i]=i; 36 for(int i=1;i<=tot1;i++){ 37 if(fid(sn[i].x)!=fid(sn[i].y)){ 38 pre[fid(sn[i].x)]=fid(sn[i].y); 39 tt++; 40 } 41 } 42 int num=0; 43 for(int i=1;i<=tot2;i++){ 44 if(fid(er[i].x)!=fid(er[i].y)){ 45 pre[fid(er[i].x)]=fid(er[i].y); 46 vis[i]=1; 47 num++;tt++; 48 } 49 } 50 if(tt<n-1||num>k)goto no; 51 52 for(int i=1;i<=n;i++)pre[i]=i; 53 for(int i=1;i<=tot2;i++){ 54 if(vis[i]){ 55 pre[fid(er[i].x)]=fid(er[i].y); 56 pt[++ans][1]=er[i].x; 57 pt[ ans][2]=er[i].y; 58 pt[ ans][3]=0; 59 if(ans==k)break; 60 } 61 } 62 for(int i=1;i<=tot2;i++){ 63 if(vis[i])continue; 64 if(fid(er[i].x)!=fid(er[i].y)){ 65 pre[fid(er[i].x)]=fid(er[i].y); 66 pt[++ans][1]=er[i].x; 67 pt[ ans][2]=er[i].y; 68 pt[ ans][3]=0; 69 if(ans==k)break; 70 } 71 } 72 if(ans<k)goto no; 73 for(int i=1;i<=tot1;i++){ 74 if(fid(sn[i].x)!=fid(sn[i].y)){ 75 pre[fid(sn[i].x)]=fid(sn[i].y); 76 pt[++ans][1]=sn[i].x; 77 pt[ ans][2]=sn[i].y; 78 pt[ ans][3]=1; 79 if(ans==n-1)break; 80 } 81 } 82 if(ans<n-1)goto no; 83 for(int i=1;i<=ans;i++) 84 printf("%d %d %d\n",pt[i][1],pt[i][2],pt[i][3]); 85 return 0; 86 no: 87 printf("no solution\n"); 88 return 0; 89 }
View Code

[luogu]P3623 [APIO2008]免費道路