• 185. [USACO Oct08] 挖水井


    185. [USACO Oct08] 挖水井

    ★★   输入文件:water.in   输出文件:water.out   简单对比
    时间限制:1 s   内存限制:128 MB

    农夫约翰决定给他的N(1<=N<=300)个牧场浇水,这些牧场被自然的命名为1..N。他可以给一个牧场引入水通过在这个牧场挖一口井或者修一条管道使这个牧场和一个已经有水的牧场连接。

    在牧场i挖一口井的花费是w_i(1<=w_i<=100000)。修建一条水管连接牧场i和牧场j的花费是p_ij(1<=p_ij<=100000;p_ij=p_ji;p_ii=0)。

    请确定农夫约翰为了完成浇灌所有的牧场所需的最小的总花费。

    题目名称:water

    输入格式:

    • 第1行:一个单独的整数n。
    • 第2..n+1行:第i+1行包含一个单独的整数w_i。
    • 第n+2..2n+1行:第n+1+i行包含n个用空可分开的整数;其中第j个数是p_ij。

    输入样例(file water.in):

    4
    5
    4
    4
    3
    0 2 2 2
    2 0 3 3
    2 3 0 4
    2 3 4 0
    

    输入说明:

    这里有4个牧场,修井和修管道的代价如图。

    输出格式:

    • 第1行:一个单独的整数,表示花费。

    输出样例(file water.out):

    9
    

    输出说明:

    农夫约翰可以在第4个牧场修井,并且将每个牧场和第一个连接起来,这样,花费是3+2+2+2=9。

    思路:一看到最小花费,就应该想到Kruskal算法,但是这个题有一个不同的地方就是多了一个挖水井的花费,这样的话我们要想用Kruskal算法解题就应该把他挖水井所用的花费一起加入到边中。我们可以将第i条边接到第n+1(这个本身不存在)条边上,这样在来跑Kruskal,跑出来的就一定是最小话费

        其实这道题理论上用贪心也可以,我一开始就是这么做的,无奈贪心的时候逻辑太混乱,贪到最后都不知道应该贪谁了。。。。。(但自测贪心可以过n<=4的所有情况)、

     

    错因:1.思路没打开

       2.贪心没贪好

     1 #include<iostream>
     2 #include<cstdio>
     3 #include<cstring>
     4 #include<algorithm>
     5 using namespace std;
     6 const int MAXN=100001;
     7 const int maxn=0x7fffffff;
     8 int n;
     9 int w[MAXN];
    10 int f[MAXN];
    11 struct node
    12 {
    13     int u;
    14     int v;
    15     int w;
    16 }edge[MAXN];
    17 int num=1;
    18 int comp(const node & a,const node & b)
    19 {
    20     if(a.w<b.w)
    21     return 1;
    22     else 
    23     return 0;
    24 }
    25 int find(int x)
    26 {
    27     if(f[x]!=x)
    28     f[x]=find(f[x]);
    29     return f[x];
    30 }
    31 void unionn(int x,int y)
    32 {
    33     int fx=find(x);
    34     int fy=find(y);
    35     f[fx]=fy;
    36 }
    37 int main()
    38 {
    39     freopen("water.in","r",stdin);
    40     freopen("water.out","w",stdout);
    41     scanf("%d",&n);
    42     for(int i=1;i<=n;i++)f[i]=i;
    43     for(int i=1;i<=n;i++)
    44         scanf("%d",&w[i]);
    45     for(int i=1;i<=n;i++)
    46     {
    47         for(int j=1;j<=n;j++)
    48         {
    49             scanf("%d",&edge[num].w);
    50             edge[num].u=i;
    51             edge[num].v=j;
    52             num++;
    53         }
    54     }
    55     for(int i=1;i<=n;i++)//  将挖水井所需要的花费做成一条从i到n+1的边 
    56     {
    57         edge[num].u=i;
    58         edge[num].v=n+1;
    59         edge[num].w=w[i];
    60         num++;
    61         edge[num].u=edge[num-1].v;
    62         edge[num].v=edge[num-1].u;
    63         edge[num].w=w[i];
    64         num++;
    65     }
    66     sort(edge+1,edge+num,comp);
    67     int k=0;
    68     long long int tot=0;
    69     for(int i=1;i<=num;i++)
    70     {
    71         if(find(edge[i].u)!=find(edge[i].v))
    72         {
    73             unionn(edge[i].u,edge[i].v);
    74             tot=tot+edge[i].w;
    75             k++;
    76         }
    77         if(k==n)
    78         break;
    79     }
    80     printf("%lld",tot);
    81     return 0;
    82 }

    贪心代码:

      1 #include<iostream>
      2 #include<cstdio>
      3 #include<cstring>
      4 #include<algorithm>
      5 #include<cmath>
      6 #include<queue>
      7 #include<stack>
      8 using namespace std;
      9 const int MAXN=100001;
     10 const int maxn=0x7fffffff;
     11 int wa[MAXN];
     12 int vis[MAXN];// 记录每个点是否已经被挖 
     13 int map[1001][1001];
     14 struct node
     15 {
     16     int u;
     17     int v;
     18     int w;
     19     int next;
     20 }edge[MAXN]; 
     21 int num=1;
     22 int head[MAXN];
     23 long long int tot;// 结果 
     24 int k;// 建立树 需要的边数 
     25 int n;
     26 int flag2=0;//记录到底有没有挖坑 
     27 int kcomp(const node & a,const node & b)
     28 {
     29     if(a.w<b.w)
     30     return 1;
     31     else return 0;
     32 }
     33 void find()//  找出不需要参与建立最小生成树的边 并删除 
     34 {
     35     for(int i=1;i<=n;i++)
     36     {
     37         int flag=1;// 默认需要挖 
     38         for(int j=head[i];j!=-1;j=edge[j].next)
     39         {
     40             if(edge[j].w<wa[i]&&edge[j].u!=edge[j].v)
     41             {
     42                 flag=0;
     43                 break;
     44             }
     45         }
     46         if(flag==1)
     47         {
     48             if(flag2==1)k--;
     49             flag2=1;
     50             tot=tot+wa[i];
     51             wa[i]=maxn;// 删除这个点 
     52             vis[i]=1;
     53             
     54         }
     55     }
     56 } 
     57 void kruskal()
     58 {
     59     for(int i=1;i<=num;i++)
     60     {
     61         if(k==0)break;
     62         if((vis[edge[i].u]==0||vis[edge[i].v]==0)||(map[edge[i].u][edge[i].v]==0))
     63         {
     64             if(edge[i].v<=edge[i].u)
     65             continue;
     66             if(vis[edge[i].u]==0)
     67             vis[edge[i].u]=1;
     68             else if(vis[edge[i].v]==0)
     69             vis[edge[i].v]=1;
     70             map[edge[i].u][edge[i].v]=1;
     71             map[edge[i].v][edge[i].u]=1;
     72             tot=tot+edge[i].w;
     73             k--;
     74         }
     75     }
     76 }
     77 int main()
     78 {
     79     freopen("water.in","r",stdin);
     80     freopen("water.out","w",stdout);
     81     scanf("%d",&n);
     82     for(int i=1;i<=n;i++)head[i]=-1;
     83     k=n-1;
     84     for(int i=1;i<=n;i++)
     85         scanf("%d",&wa[i]);
     86     for(int i=1;i<=n;i++)
     87     {
     88         for(int j=1;j<=n;j++)
     89         {
     90             scanf("%d",&edge[num].w);
     91             edge[num].u=i;
     92             edge[num].v=j;
     93             edge[num].next=head[i];
     94             head[i]=num++;
     95         }
     96     } 
     97     find();//  找出不需要参与建立最小生成树的边 
     98     sort(edge+1,edge+num,kcomp);
     99     kruskal();// 用剩余的边建立最小生成树 
    100     sort(wa+1,wa+1+n);
    101     if(wa[1]!=maxn&&flag2==0)
    102     tot=tot+wa[1];
    103     printf("%lld",tot);
    104     fclose(stdin);
    105     fclose(stdout);
    106     return 0;
    107 }
  • 相关阅读:
    机器学习初篇(0.0)
    MQTT 入门介绍
    《八极拳谱》(李书文)
    Golang实战群:日志的处理机制
    【转】火山引擎 Redis 云原生实践
    【转】7000字前端性能优化总结 | 干货建议收藏
    微信小程序canvas绘制圆角边框
    【转】语义化版本 2.0.0
    Verdaccio私有 npm 服务器搭建及其配置
    【转】根据条件配置多个npm仓库
  • 原文地址:https://www.cnblogs.com/zwfymqz/p/6730923.html
Copyright © 2020-2023  润新知