P3623 [APIO2008]免费道路 WQS二分

题意:

题意

分析:

手动给边权赋值,转化成 PP2619 [国家集训队2]Tree I

代码:

#include<bits/stdc++.h>

using namespace std;

namespace zzc 
{
	const int maxn = 2e4+5;
	const int maxm = 100005;
	const double eps = 1e-5;
	int fa[maxn];
	int n,m,need,tot,cnt;
	bool vis[maxm];

	struct edge 
	{
		int frm,to,nxt,flag;
		double val;
	}e[maxm];

	bool cmp(edge a,edge b) 
	{
		if(a.val==b.val) return a.flag<b.flag;
		return a.val<b.val;
	}

	int find(int u) 
	{
		return fa[u]==u?u:fa[u]=find(fa[u]);
	}

	void init() 
	{
		scanf("%d%d%d",&n,&m,&need);
		for(int i=1;i<=m;i++) 
		{
			scanf("%d%d%d",&e[i].frm ,&e[i].to,&e[i].flag);
			e[i].val=rand()%m;
		}
	}
    
    void kruskal()
    {
    	sort(e+1,e+m+1,cmp);
    	for(int i=1;cnt!=n-1;i++)
		{
          int fx=find(e[i].frm),fy=find(e[i].to);
          if(fx!=fy)
		  {
		 	   vis[i]=true;
         	   cnt++;
               fa[fx]=fy;
               if(e[i].flag==0) tot++;
          } 
       }
	}

	void solve() 
	{
		double l=-2e5+5,r=2e5+5;
		while(r-l>=eps) 
		{
			double mid=(l+r)/2.0;
			for(int i=1;i<=m;i++) 
			{
				if(!e[i].flag) e[i].val+=mid;
				vis[i]=false;
			}
			for(int i=1;i<=n+1; i++) fa[i]=i;
			cnt=0,tot=0;
			kruskal();
			if(tot>=need) l=mid+1;
			else r=mid-1;
			if(tot==need)
			{
				for(int i=1;i<=m;i++) if(vis[i]) printf("%d %d %d\n",e[i].frm,e[i].to,e[i].flag);
				return ;
			}
			for(int i=1; i<=m; i++) if(e[i].flag==0)e[i].val-=mid;
		}
		printf("no solution\n");
	}
    
    void work()
    {
    	srand(time(0));
    	init();
    	solve();
	}

}

int main() 
{
	zzc::work();
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值