習題:Fools and Foolproof Roads(貪心)
阿新 • • 發佈:2020-08-24
題目
思路
跟合併果子類似的思路
程式碼
#include<iostream> #include<cstdio> #include<queue> using namespace std; namespace ufs { int fa[100005]; long long w[100005]; void makeset(int n) { for(int i=1;i<=n;i++) fa[i]=i; } int findset(int x) { if(fa[x]==x) return x; return fa[x]=findset(fa[x]); } void merge(int u,int v,int s) { int a=findset(u); int b=findset(v); if(a==b) w[a]+=s; else { fa[a]=b; w[b]=w[b]+w[a]+s; } } } using namespace ufs; struct node { int id; long long w; friend bool operator < (const node &a,const node &b) { return a.w>b.w; } }; int n,m,p,q; int cnt; priority_queue<node> Q; int main() { ios::sync_with_stdio(false); cin>>n>>m>>p>>q; makeset(n); for(int i=1,u,v,s;i<=m;i++) { cin>>u>>v>>s; merge(u,v,s); } for(int i=1;i<=n;i++) if(i==findset(i)) { Q.push((node){i,w[i]}); cnt++; } if(cnt-p>q||cnt<q||(m==0&&q-n==0&&p)) { cout<<"NO"; return 0; } else cout<<"YES\n"; while(cnt>q) { node t1=Q.top(); Q.pop(); node t2=Q.top(); Q.pop(); p--; cnt--; merge(t1.id,t2.id,t1.w+t2.w+min(1000000000ll,t1.w+t2.w+1)); Q.push((node){t1.id,t1.w+t2.w+min(1000000000ll,t1.w+t2.w+1)}); cout<<t1.id<<' '<<t2.id<<'\n'; } for(int i=1;i<=n;i++) { if(i!=fa[i]) { for(int j=1;j<=p;j++) cout<<i<<' '<<fa[i]<<'\n'; break; } } return 0; }