bzoj3624:[Apio2008]免費道路
阿新 • • 發佈:2019-03-05
i++ efi 情況 www oid names printf ace pac
傳送門
顯然是求生成樹
只有兩種情況會導致no solution:
1、如何加邊圖都不連通
2、必須要加的鵝卵石邊超過k條
首先可以一遍kruskal判斷出必須要加的鵝卵石邊是多少:優先加水泥路的邊
然後將必須要加的鵝卵石邊加上去,再多加幾條邊使鵝卵石邊等於k條,再去加水泥路
最後判斷圖是否聯通就行了(也就是加的邊數是否是n-1條)
現在考慮正確性:由於一開始處理出了必須要加的鵝卵石邊,所以其他的鵝卵石邊和水泥路邊都是可以互相替換的,這樣就可以保證剩下的邊可以隨便加了
代碼:
#include<cstdio> #include<iostream> #include<algorithm> using namespace std; void read(int &x) { char ch; bool ok; for(ok=0,ch=getchar(); !isdigit(ch); ch=getchar()) if(ch=='-') ok=1; for(x=0; isdigit(ch); x=x*10+ch-'0',ch=getchar()); if(ok) x=-x; } #define rg register const int maxn=1e5+10; int n,m,k,tot,f[maxn],ans,cnt,h[maxn]; struct oo{int x,y,z;}a[maxn];bool vis[maxn]; int find(int x){return x==f[x]?x:f[x]=find(f[x]);} bool cmp(oo a,oo b){return a.z>b.z;} int main() { read(n),read(m),read(k); for(rg int i=1;i<=n;i++)f[i]=i; for(rg int i=1;i<=m;i++)read(a[i].x),read(a[i].y),read(a[i].z); sort(a+1,a+m+1,cmp); for(rg int i=1;i<=m;i++) if(find(a[i].x)!=find(a[i].y)) { int x=find(a[i].x),y=find(a[i].y);f[x]=y; if(!a[i].z)ans++,vis[i]=1; } if(ans>k){printf("no solution\n");return 0;} for(rg int i=1;i<=n;i++)f[i]=i; for(rg int i=m;i;i--) if(vis[i]){int x=find(a[i].x),y=find(a[i].y);f[x]=y;} for(rg int i=m;i;i--) if(find(a[i].x)!=find(a[i].y)) { int x=find(a[i].x),y=find(a[i].y);f[x]=y; if(!a[i].z)ans++,vis[i]=1; if(ans==k)break; } for(rg int i=1;i<=m;i++) if(find(a[i].x)!=find(a[i].y)) { int x=find(a[i].x),y=find(a[i].y);f[x]=y; vis[i]=1;if(!a[i].z)break; } for(rg int i=1;i<=m;i++)if(vis[i])tot++; if(tot<n-1){printf("no solution\n");return 0;} for(rg int i=1;i<=m;i++)if(vis[i])printf("%d %d %d\n",a[i].x,a[i].y,a[i].z); }
bzoj3624:[Apio2008]免費道路