【SOJ 973】Tree

emmm……

今天第二题正解代码有点复杂,我先写第三题

【题目】

题目描述:

给你一个有 N 个点 M 条边的无向带权连通图,每条边是白色或黑色,求一颗最小权的恰好有 K 条白边的生成树。

输入格式:

第一行三个数 N、M、K ,分别表示点数、边数和所需的白边数。
接下来 M 行,每行四个数 u、v、w、c ,分别表示一条边的两个端点(从0开始标号)、边权和颜色(0表示白色,1表示黑色)。
输入数据保证有解。

输出格式:

一行一个数表示所求生成树的边权和。

样例数据:

输入
2 2 1
0 1 1 1
0 1 2 0

输出
2

备注:

【数据范围】
对 20% 的输入数据 :1≤N≤15。 
对 100% 的输入数据 :1≤N≤50000,1≤M≤100000,1≤w≤100。

【分析】

看到这道题,很容易想到最小生成树,但是加上了选 K 条白边的限制,这该怎么办呢?

如果直接用最小生成树的话,不能够保证能选 K 条白边,我们就要通过一个操作让它选 K 条边

正解的做法就是将所有白边的权值加上(或减去)一个值,使得这样做了之后最小生成树能恰好选出 K 条白边

怎么确定这个值呢?用二分,由于边权最多为 100,所以我们就在 -100 ~ 100 之间二分

在计算答案的时候将二分出的值补回去就可以了

至于证明嘛……大家感性理解一下就行了,因为本蒟蒻也不会

【代码】

这里注意一下代码中易错的两个地方:

  1. 排序时,在权值相等的情况下,要么让白边全在前面,要么让黑边全在前面,不然有可能会破坏二分的单调性
  2. 在二分完输出答案前,还要做一遍最小生成树,不然的话,答案是最后一次二分时的答案,而不是最终答案
#include<cstdio>
#include<cstring>
#include<algorithm>
#define N 200005
using namespace std;
int n,m,k,sum;
int x[N],y[N],z[N],c[N],father[N];
struct node
{
	int u,v,w,c;
}a[N];
bool comp(const node &p,const node &q)
{
	if(p.w!=q.w)
	  return p.w<q.w;
	return p.c<q.c;
}
int find(int x)
{
	if(father[x]!=x)
	  father[x]=find(father[x]);
	return father[x];
}
void add(int x,int y,int z,int c,int i)
{
	a[i].u=x;
	a[i].v=y;
	a[i].w=z;
	a[i].c=c;
}
bool Kruskal(int mid)
{
	int i,p,q,num=0,ans=0;
	for(i=0;i<n;++i)
	  father[i]=i;
	for(i=1;i<=m;++i)
	{
		add(x[i],y[i],z[i],c[i],i);
		if(c[i]==0)
		  a[i].w+=mid;
	}
	sort(a+1,a+m+1,comp);
	sum=0;
	for(i=1;i<=m;++i)
	{
		p=find(a[i].u);
		q=find(a[i].v);
		if(p!=q)
		{
			num++;
			sum+=a[i].w;
			father[p]=q;
			if(a[i].c==0)
			  ans++;
		}
		if(num==n-1)
		  break;
	}
	if(ans>=k)
	  return true;
	return false;
}
int main()
{
//	freopen("tree.in","r",stdin);
//	freopen("tree.out","w",stdout);
	int l,r,i,mid;
	scanf("%d%d%d",&n,&m,&k);
	for(i=1;i<=m;++i)
	  scanf("%d%d%d%d",&x[i],&y[i],&z[i],&c[i]);
	l=-100,r=100;
	while(l<r)
	{
		mid=(l+r+1)>>1;
		if(Kruskal(mid))  l=mid;
		else  r=mid-1;
	}
	Kruskal(l);
	printf("%d",sum-k*l);
// 	fclose(stdin);
// 	fclose(stdout);
    return 0;
}

猜你喜欢

转载自blog.csdn.net/forever_dreams/article/details/81187848