灌溉

 

【问题描述】

Farmer John 有𝑛个牧场,他希望灌溉他的所有牧场。牧场编号为1 ∼ 𝑛,要灌溉一个牧场有两种方式,一个是直接在这个牧场建设一个小型水库,另一个是从别的牧场向这个牧场引水。在第𝑖个牧场建立小型水库需要𝑊%美元,而从第𝑖 个

牧场向第𝑗个牧场引水需要𝑃%,<美元。即便牧场𝑗没有建设小型水库,只要有别的有

水的水库向它引水,那它自己也有水,而且可以向别的水库引水。请告诉 FJ 灌溉所有牧场所需的最小代价。

【输入格式】

输入数据的第一行包含一个整数𝑛,代表牧场的数目。

接下来𝑛行,每行包含一个整数𝑊%,代表建立小型水库的代价。接下来𝑛行,每行包含𝑛个整数。第𝑖行的第𝑗个数为𝑃%,<。

【输出格式】

输出一行,包含一个整数,即为答案。

【样例】

irrigate.in

irrigate.out

4

9

5

4

4

3

0 2 2 2

2 0 3 3

2 3 0 4

2 3 4 0

【样例解释】

FJ 应该在第 4 块牧场上建立小型水库,然后从这块牧场向其他所有牧场引水。总费用为3 + 2 + 2 + 2 = 9美元。

【数据规模和约定】

对于 20%的数据,𝑛 ≤ 10。

对于 40%的数据,𝑛 ≤ 50。对于 60%的数据,𝑛 ≤ 100。

对于 100%的数据,1 ≤ 𝑛 ≤ 300,1 ≤ 𝑃%,<, 𝑊% ≤ 10>,𝑃%,< = 𝑃<,%,𝑃%,% = 0。

这个题如果不考虑自己建水库的情况,那么就是找一个最小生成树的模板问题,二而且n比较小,所以prim就可以解决。

那如果加上建水库的情况,本来考虑在比较的时候加上一个建水库的比较,但是只能过一半的点。

然后想了很久,如果在比较的时候加上建水库的情况的话,那么前面取进行更新的点时,就不能保证取到的点时最有的那一个。

然后就懵逼的没思路了。。。。。。

然后同桌说了一个很精辟的思路,将dis数组赋值为建水库的花费,突然感到很有道理,我们没有必要非得建成一棵树,我们可以先将每一个点都看做一棵树,那么如果这个点与别的点组成树比自己成为一棵树要优的话,那么就不将其加入到树中,但是这与将其加入树中的影响是相同的,只不过ans加的是其建成水站的费用,而不是与另外的点连接的花费。然后就愉快的结束了。

附上代码

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<iostream>
 4 using namespace std;
 5 int n,a[310][310],s[310],dis[310],vis[310],Min=0x7fffffff,ans;
 6 bool bz=0;
 7 int main()
 8 {
 9     scanf("%d",&n);
10     for(int i=1;i<=n;++i)
11     {
12         scanf("%d",&dis[i]);
13     }
14     for(int i=1;i<=n;++i)
15     {
16         for(int j=1;j<=n;++j)
17         {
18             scanf("%d",&a[i][j]);
19         }
20     }
21     dis[0]=0x7ffffff;
22     for(int i=1;i<n;++i)
23     {
24         int k=0;
25         for(int j=1;j<=n;++j)
26         {
27             if(!vis[j]&&dis[j]<dis[k])
28             {
29                 k=j;
30             }
31         }
32         vis[k]=1;
33         for(int j=1;j<=n;++j)
34         {
35             if(!vis[j])
36             dis[j]=min(dis[j],a[k][j]);
37         }
38     }
39     for(int i=1;i<=n;++i)
40     {
41         ans+=dis[i];
42     }
43     printf("%d",ans);
44     return 0;
45 }