把博客园图标替换成自己的图标
把博客园图标替换成自己的图标end

APIO2013 道路费用【最小生成树】

题目链接

题目解析

根据\(k\)的范围,不难想到我们\(2^k\)枚举所有新边是否在\(MST\)中,然后再加入原始边,计算出答案取最值。

但是这样做复杂度过不去。

先考虑把\(k\)条新边加进去,然后再按照\(Kruskal\)算法加入\(n-1-k\)条原始边,形成一棵树。由于原始边的权值各不相同,那么目前加入的这些原始边集合是唯一确定的。

又因为在\(MST\)里的新边条数最多为\(k\),那么加入的原始边数量不会比现在更少,又是从小到大加边,目前已经加入的原始边一定一直在\(MST\)中。

所以我们可以把这些固定的原始边连在一起,进行缩点。

那么现在图中只剩下\(k+1\)个结点了(我们还差\(k\)条边没有连,想成一棵\(k\)条边的树,结点个数就是\(k+1\)了)

诶嘿,然后我们现在发现刚才的那个做法,它又可以了,所以那么做就行了。


►Code View

#include<cstdio>
#include<algorithm>
#include<vector>
#include<queue>
#include<cstring>
using namespace std;
#define N 100005
#define M 200005
#define INF 0x3f3f3f3f
#define LL long long
int rd()
{
	int x=0,f=1;char c=getchar();
	while(c<'0'||c>'9'){if(c=='-')f=-1; c=getchar();}
	while(c>='0'&&c<='9'){x=(x<<1)+(x<<3)+(c^48);c=getchar();}
	return f*x;
}
struct node{
	int u,v,w;
}e[M],g[25],e2[M];
int cnt;
bool cmp(node p,node q)
{
	return p.w<q.w;
}
int n,m,k;
int p[N],pe[N];
int id[N],tot;
int rt;
struct un{
	int f[N];
	void Init()
	{
		for(int i=1;i<=n;i++)
			f[i]=i,f1[i]=i;
	}
	int Find(int x)
	{
		if(f[x]==x) return x;
		return f[x]=Find(f[x]);
	}
	bool Union(int u,int v)
	{
		u=Find(u),v=Find(v);
		if(u==v) return 0;
		if(u<v) f[u]=v;
		else f[v]=u;
		return 1;
	}
}A,B;

int main()
{
	n=rd(),m=rd(),k=rd();
	A.Init();
	B.Init();
	for(int i=1;i<=m;i++)
		e[i].u=rd(),e[i].v=rd(),e[i].w=rd();
	for(int i=1;i<=k;i++)
	{
		g[i].u=rd(),g[i].v=rd();
		A.Union(g[i].u,g[i].v);
	}
	for(int i=1;i<=n;i++)
		p[i]=rd();
	sort(e+1,e+m+1,cmp);
	int num=k;
	for(int i=1;i<=m;i++)
	{
		if(A.Union(e[i].u,e[i].v))
		{
			num++;
			B.Union(e[i].u,e[i].v);
		}
		if(num==n-1) break;
	}
	for(int i=1;i<=n;i++)
		if(B.Find(i)==i)
			id[i]=++tot;//缩点
	for(int i=1;i<=n;i++)
		pe[id[B.Find(i)]]+=p[i];//缩点
	rt=id[B.Find(1)];
	A=B;
	for(int i=1;i<=m;i++)
		if(B.Union(e[i].u,e[i].v))
			e2[++cnt]=e[i];//可能加入的原始边
	for(int i=1;i<=k;i++)
		g[i].u=id[A.Find(g[i].u)],g[i].v=id[A.Find(g[i].v)];//缩点
	for(int i=1;i<=cnt;i++)
		e2[i].u=id[A.Find(e2[i].u)],e2[i].v=id[A.Find(e2[i].v)];//缩点
	
	for(int S=0;S<(1<<k);S++)
	{
		
	}
	return 0;
}



posted @ 2020-11-26 16:12  Starlight_Glimmer  阅读(64)  评论(0编辑  收藏  举报
浏览器标题切换
浏览器标题切换end