zoukankan      html  css  js  c++  java
  • [bzoj1601]灌水_kruskal

    灌水 bzoj-1601

        题目大意:给你n块地,将两块地之间连通有代价$P_{i,j}$,单独在一块地打井需要代价$C_i$,问将所有的井都有水的代价是多少。

        注释:1<=n<=300.

          想法:这种题做过一遍就好了,我们新建立一个0号节点。如果两块地之间打通就在这两个点之间连边。如果这个点单独打井就将这个点与新建节点连边,权值为打井代价。然后跑最小生成树。首先我们知道,这n块地中至少有一块地是打井的,不然就算所有的点都连通,也是没有水的。所以,这个强大的算法显然是正确的。

        最后,附上丑陋的代码... ...

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    using namespace std;
    struct Node
    {
    	int a,b,val;
    }f[1001000];
    int fa[10001];
    bool cmp(Node a,Node b)
    {
    	return a.val<b.val;
    }
    int find(int x)
    {
    	return x==fa[x]?x:(fa[x]=find(fa[x]));
    }
    bool merge(int x,int y)
    {
    	x=find(x);y=find(y);
    	if(x==y) return false;
    	fa[x]=y;return true;
    }
    int main()
    {
    	int n;
    	scanf("%d",&n);
    	int cnt=0;
    	for(int i=0;i<=n;i++) fa[i]=i;
    	for(int i=1;i<=n;i++)//向0号节点加边
    	{
    		int x;
    		scanf("%d",&x);
    		f[++cnt].a=0;
    		f[cnt].b=i;
    		f[cnt].val=x;
    	}
    	for(int i=1;i<=n;i++)//邻接矩阵,地与地之间的联通代价
    	{
    		for(int j=1;j<=n;j++)
    		{
    			int x;
    			cin >> x;
    			if(i>j)
    			{
    				f[++cnt].a=i;
    				f[cnt].b=j;
    				f[cnt].val=x;
    			}
    		}
    	}
    	sort(f+1,f+cnt+1,cmp);
    	int count=0;
    	int ans=0;
    	for(int i=1;i<=cnt;i++)//kruskal
    	{
    		if(merge(f[i].a,f[i].b))
    		{
    			ans+=f[i].val;
    			count++;
    		}
    		if(count==n) break;//注意,我们是在跑n+1个点的kruskal,所以count的退出条件是count==n
    	}
    	printf("%d
    ",ans);
    	return 0;
    }
    

         小结:思路题,超级好玩的qwq

  • 相关阅读:
    win8及win8.1商店出现0X80073CF9的解决办法!
    Ubuntu 14.04 登陆界面循环问题解决
    Java学习笔记-Json
    Java学习笔记-Thread-线程
    git学习笔记
    Java学习笔记-File
    java学习笔记-set
    C# 实验4 数据库
    C#文件处理
    C#-实验3
  • 原文地址:https://www.cnblogs.com/ShuraK/p/8612040.html
Copyright © 2011-2022 走看看