1. 程式人生 > 實用技巧 >習題:Fools and Foolproof Roads(貪心)

習題: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;
}