1. 程式人生 > >[bzoj1601]灌水_kruskal

[bzoj1601]灌水_kruskal

scan n) 條件 sca += 如果 font == cin

灌水 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\n",ans);
	return 0;
}

    小結:思路題,超級好玩的qwq

[bzoj1601]灌水_kruskal