• 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;
    }
    
    
    
    
  • 相关阅读:
    求正方形的面积和周长
    面向对象练习——校园管理系统
    python--面向对象(最全讲解)
    git删除远程仓库的文件或目录
    git设置忽略文件和目录
    计算器
    织梦标签整理
    比较恶心的360老年版浏览器 文件导出下载
    织梦文章列表样式多元化实现
    php函数整理
  • 原文地址:https://www.cnblogs.com/lyttt/p/14033297.html
Copyright © 2020-2023  润新知