Watering Hole
Source : USACO 2008 Open | |||
Time limit : 1 sec | Memory limit : 64 M |
Submitted : 71, Accepted : 48
Farmer John has decided to bring water to his N (1 <= N <= 300) pastures which are conveniently numbered 1..N. He may bring water to a pasture either by building a well in that pasture or connecting the pasture via a pipe to another pasture which already has water.
Digging a well in pasture i costs W_i (1 <= W_i <= 100,000). Connecting pastures i and j with a pipe costs P_ij (1 <= P_ij <= 100,000; P_ij = P_ji; P_ii=0).
Determine the minimum amount Farmer John will have to pay to water all of his pastures.
INPUT FORMAT
* Line 1: A single integer: N
* Lines 2..N + 1: Line i+1 contains a single integer: W_i
* Lines N+2..2N+1: Line N+1+i contains N space-separated integers; the j-th integer is P_ij
SAMPLE INPUT
4 5 4 4 3 0 2 2 2 2 0 3 3 2 3 0 4 2 3 4 0
INPUT DETAILS
There are four pastures. It costs 5 to build a well in pasture 1, 4 in pastures 2 and 3, 3 in pasture 4. Pipes cost 2, 3, and 4 depending on which pastures they connect.
OUTPUT FORMAT
* Line 1: A single line with a single integer that is the minimum cost of providing all the pastures with water.
SAMPLE OUTPUT
9
OUTPUT DETAILS
Farmer John may build a well in the fourth pasture and connect each pasture to the first, which costs 3 + 2 + 2 + 2 = 9.
题目分析:
咋一看上去似乎无解,如果是DP的话,每个pastures被浇水的选择有两种:一种是打井,一种是从其他的pastures连接水管,但是状态呢?这个状态要能够记录一个集合里那些是被浇过水的哪些待浇水的,300个定点状态达到2^300,无解; 我还想过用最小费用最大流的方式,把打井抽象出来一个节点然后该节点向每个pastures连接边流量为n,费用为对应pastures打井的费用,然后新修一个虚拟节点汇点,流量为1费用为0,这样做结果显然不对的。
比较优美的解法是最小生成树,把打井抽象出一个节点0,其他的pastures分别用1 ~ n表示。
代码都不解释了,一般提到最小生成树都可以想出来了
#include<iostream>
using namespace std;
int g[310][310];
int dist[310];
bool vis[310];
int prime(int n)
{
memset(vis,0,sizeof(vis));
int ans = 0;
for(int i=0;i<=n;i++)
{
dist[i] = g[0][i];
vis[i] = 0;
}
vis[0] = 1;
for(int i=0;i<n;i++)
{
int k = -1,Min = 99999999;
for(int j=0;j<=n;j++)
if(!vis[j] && Min > dist[j]) {
k = j;
Min = dist[j];
}
vis[k] = 1;
ans += Min;
for(int j=0;j<=n;j++)
if(!vis[j]&&dist[j] > g[k][j])
dist[j] = g[k][j];
}
return ans;
}
int main()
{
int n;
scanf("%d",&n);
for(int i=0;i<=n;i++)
for(int j=1;j<=n;j++)
scanf("%d",&g[i][j]);
for(int i=1;i<=n;i++)
g[i][0] = g[0][i];
/*for(int i=0;i<=n;i++)
{
for(int j=0;j<=n;j++)
cout << g[i][j] << " ";
cout << endl;
}*/
printf("%d\n",prime(n));
return 0;
}
/*
4
5
4
4
3
0 2 2 2
2 0 3 3
2 3 0 4
2 3 4 0
*/