卧薪尝胆,厚积薄发。
USACO2008 OCT 灌水
Date: Tue Jul 17 00:07:27 CST 2018 In Category: NoCategory

Description:

把一块土地进行灌水有两种方法,从其他农田饮水,或者这块土地建造水库。 建造一个水库需要花费 $w_i$ ,连接两块土地需要花费 $P_{ij}$ 。计算 $Farmer$ $John$ 所需的最少代价
$1\le N\le 300$

Solution:

首先每个点都有两种决策,从别的点引水或者新建,所以我们可以增加一个超级源点。然后每个源点向每个点都连边,每条边的边权是在这个点建立水库的费用,然后点之间互相连边,最后一次最小生成树就可以了。

Code:


#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<cstdio>
#include<cmath>
#include<cstring>
using namespace std;
int n;
#define MAXN 310
struct edge
{
int u,v,w;
}e[MAXN * MAXN * 2];
int edgenum = 0;
void add(int a,int b,int c)
{
++edgenum;e[edgenum].u = a;e[edgenum].v = b;e[edgenum].w = c;
return;
}
bool cmp(edge x,edge y){return x.w < y.w;}
int f[MAXN];
int find(int x){return (x == f[x] ? x : f[x] = find(f[x]));}
int main()
{
scanf("%d",&n);
int a;
for(int i = 1;i <= n;++i)
{
scanf("%d",&a);
add(i,n + 1,a);
}
for(int i = 1;i <= n;++i)
{
for(int j = 1;j <= n;++j)
{
scanf("%d",&a);
add(i,j,a);
}
}
sort(e + 1,e + 1 + edgenum,cmp);
for(int i = 1;i <= n;++i)f[i] = i;
int ans = 0;
for(int i = 1;i <= edgenum;++i)
{
int p = find(e[i].u),q = find(e[i].v);
if(p == q)continue;
f[p] = q;
ans += e[i].w;
}
cout << ans << endl;
return 0;
}
In tag: 图论-kruskal
Copyright © 2020 wjh15101051
ღゝ◡╹)ノ♡