习题:Fools and Foolproof Roads(贪心)
题目
思路
跟合并果子类似的思路
代码
#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;
}

浙公网安备 33010602011771号