• 洛谷 题解 P1550 【[USACO08OCT]打井Watering Hole】


    本题看似很难,实际上思路非常简单——如果你想通了。

    首先有一个问题:图中有几个点?大部分的人会回答(n)个点。错了,有(n+1)个。

    多出来的那个点在哪?关键在于你要理解每一个决策的意义。实际上,多出来的那个点是地下的天然矿泉水。当我们打井时,我们实际上是在往地下连边。理解了这一点,代码就没有任何难度了。

    构图时,我们只需多加一个点,对于每个点(i),我们连边(i→n+1),边权为(w_i)。然后直接跑最小生成树就没了。就没了。(转载from here)

    #include<bits/stdc++.h>
    using namespace std;
    const int MAXN=300+10;
    const int MAXM=1e5;
    int n,m;
    int fa[MAXN];
    struct Node
    {
    	int u,v,w;
    	bool operator < (const Node &x) const
    	{
    		return x.w>w;
    	}
    }edge[MAXM];
    inline int read()
    {
    	int tot=0;
    	char c=getchar();
    	while(c<'0'||c>'9')
    		c=getchar();
    	while(c>='0'&&c<='9')
    	{
    		tot=tot*10+c-'0';
    		c=getchar();
    	}
    	return tot;
    }
    inline int find(int k)
    {
    	if(fa[k]==k)return k;
    	else return fa[k]=find(fa[k]);
    }
    inline int kruskal()
    {
    	int tot=0,cnt=0;
    	for(int i=1;i<=n;i++)
    		fa[i]=i;
    	for(int i=1;i<=m;i++)
    	{
    		int fx=find(edge[i].u),fy=find(edge[i].v);
    		if(fx!=fy)
    		{
    			fa[fx]=fy;
    			tot++;
    			cnt+=edge[i].w;
    		}
    		if(tot==n-1)return cnt;
    	}
    }
    int main()
    {
    	n=read();
    	int x;
    	for(int i=1;i<=n;i++)
    	{
    		x=read();
    		edge[++m].u=i;
    		edge[m].v=n+1;
    		edge[m].w=x;
    	}
    	for(int i=1;i<=n;i++)
    	{
    		for(int j=1;j<=n;j++)
    		{
    			x=read();
    			if(i<j)
    			{
    				edge[++m].u=i;
    				edge[m].v=j;
    				edge[m].w=x;
    			}
    		}
    	}
    	n++;
    	sort(edge+1,edge+1+m);
    	printf("%d
    ",kruskal());
    	return 0;
    }
    
  • 相关阅读:
    Servlet常用类
    Java库使用----xstream1.3.1
    字符串处理---统计每一行字符串当中的字符“u”个数
    读写锁
    求阶乘
    Fibonacci数列
    22.2-按照升序显示不重复的单词
    22.1-在散列集上进行集合操作
    完美世界-2015校园招聘-java服务器工程师-成都站
    运用jQuery写的验证表单
  • 原文地址:https://www.cnblogs.com/hulean/p/11128642.html
Copyright © 2020-2023  润新知