[HNOI2006]公路修建问题 ——二分答案+krukal(蒟弱个人总结)

题目链接

题意:

题目要求我们在n个景点之间建立n-1条公路,在花费尽量少的情况下至少有k条一级公路,求花费最多的一条公路的最小花费

题解:

  • 二分答案+kruskal,在[l,r]之间二分答案,l为输入的最小花费,r为输入的最大花费
  • check函数里面跑两次kruskal,第一次选一级公路,第二次选二级公路,如果选的一级公路的条数>=k,并且一级公路数量和二级公路数量==n-1,那么return true,继续二分更小的mid;否则mid太小了,return false
  • 不能跑一次kruskal,同时选一级公路和二级公路,因为题目的要求是至少选k条一级公路,如果同时选,可能选不到k条一级公路

AC代码

#include<bits/stdc++.h>

using namespace std;
#define N 10009
#define M 20009
#define mem(a,b) memset(a,b,sizeof a)
int n,m,k,p[M];
int Find(int x)
{
	if(x!=p[x]) p[x] = Find(p[x]);
	return p[x];
}
struct Edge
{
	int a,b,c1,c2;
	bool operator <(const Edge &t) const
	{
		if(t.c1!=c1) return c1<t.c1;
		else return c2<t.c2;
	}
}edge[M];
bool check(int mid)
{
	mem(p, 0);
	int cnt1 = 0,res =0,cnt2=0;
	for(int i=1; i<=n; i++) p[i] = i;
	for(int i=0; i<m-1; i++)
	{
		int a = Find(edge[i].a),b = Find(edge[i].b);
		int c1=edge[i].c1, c2=edge[i].c2; 
		if(a!=b&&c1<=mid)
		{
			cnt1++;
			p[a] = b;
		}
	}
	if(cnt1<k) return false;
	for(int i=0; i<m-1; i++)
	{
		int a = Find(edge[i].a),b = Find(edge[i].b);
		int c1=edge[i].c1, c2=edge[i].c2; 
		if(a!=b&&c2<=mid)
		{
			cnt2++;
			p[a] = b;
		}
	}
//	cout<<mid<<" ";
	//cout<<cnt1+cnt2<<endl;
	if(cnt1+cnt2<n-1) return false;
	return true;
}
int main()
{
	scanf("%d%d%d",&n,&k,&m);
	int l=1e9,r=-1;
	for(int i=0; i<m-1; i++)
	{
		int a,b,c1,c2;
		scanf("%d%d%d%d",&a,&b,&c1,&c2);
		edge[i]={a,b,c1,c2};
		l = min(l,min(c1,c2));
		r = max(r,max(c1,c2));
	} 
	//排序与否都没关系 
//	sort(edge,edge+m-1);
	while(l<=r)
	{
		int mid = l+r>>1;
		if(check(mid)) r = mid-1;
		else l = mid+1;
		//puts("wa");
	}
	cout<<l<<endl;
	return 0;
 } 

蒟弱刷题日记,思路参考洛谷大佬博客
有错误请指出,一起进步呀!

posted @ 2022-08-28 08:44  翔村亲亲鸟  阅读(15)  评论(0编辑  收藏  举报