zoukankan      html  css  js  c++  java
  • 历届试题 城市建设

     http://lx.lanqiao.org/problem.page?gpid=T117

     历届试题 城市建设  

    时间限制:1.0s   内存限制:256.0MB
     
    问题描述
      栋栋居住在一个繁华的C市中,然而,这个城市的道路大都年久失修。市长准备重新修一些路以方便市民,于是找到了栋栋,希望栋栋能帮助他。

      C市中有n个比较重要的地点,市长希望这些地点重点被考虑。现在可以修一些道路来连接其中的一些地点,每条道路可以连接其中的两个地点。另外由于C市有一条河从中穿过,也可以在其中的一些地点建设码头,所有建了码头的地点可以通过河道连接。

      栋栋拿到了允许建设的道路的信息,包括每条可以建设的道路的花费,以及哪些地点可以建设码头和建设码头的花费。

      市长希望栋栋给出一个方案,使得任意两个地点能只通过新修的路或者河道互达,同时花费尽量小。
    输入格式
      输入的第一行包含两个整数n, m,分别表示C市中重要地点的个数和可以建设的道路条数。所有地点从1到n依次编号。
      接下来m行,每行三个整数a, b, c,表示可以建设一条从地点a到地点b的道路,花费为c。若c为正,表示建设是花钱的,如果c为负,则表示建设了道路后还可以赚钱(比如建设收费道路)。
      接下来一行,包含n个整数w_1, w_2, …, w_n。如果w_i为正数,则表示在地点i建设码头的花费,如果w_i为-1,则表示地点i无法建设码头。
      输入保证至少存在一个方法使得任意两个地点能只通过新修的路或者河道互达。
    输出格式
      输出一行,包含一个整数,表示使得所有地点通过新修道路或者码头连接的最小花费。如果满足条件的情况下还能赚钱,那么你应该输出一个负数。
    样例输入
    5 5
    1 2 4
    1 3 -1
    2 3 3
    2 4 5
    4 5 10
    -1 10 10 1 1
    样例输出
    9
    样例说明
      建设第2、3、4条道路,在地点4、5建设码头,总的花费为9。
    数据规模和约定
      对于20%的数据,1<=n<=10,1<=m<=20,0<=c<=20,w_i<=20;
      对于50%的数据,1<=n<=100,1<=m<=1000,-50<=c<=50,w_i<=50;
      对于70%的数据,1<=n<=1000;
      对于100%的数据,1 <= n <= 10000,1 <= m <= 100000,-1000<=c<=1000,-1<=w_i<=1000,w_i≠0。

    分析:

    n个城市,m条边。额外的是,每个城市还可以建码头。

    如果两个城市都有码头,则这两个城市可以互相到达。

    求最小生成树。

    对于码头,可以把所有码头都连到一个0点,代价是建码头的费用。

    这时候就跑两遍,一遍是有码头的情况,第二遍没有码头。

    这样的话就一个问题,就是如果没有码头的话,道路会不会都联通。

    然后还要注意,负数的道路是必须连的,这样费用更小!

    AC代码:

     1 #include"stdio.h"
     2 #include"algorithm"
     3 #include"string.h"
     4 #include"iostream"
     5 #include"queue"
     6 #include"map"
     7 #include"string"
     8 #define mod 1000000007
     9 using namespace std;
    10 struct node
    11 {
    12     int x,y,s;
    13 } edge[123456];
    14 int pre[12345];
    15 int cmp(node a,node b)
    16 {
    17     return a.s<b.s;
    18 }
    19 int finde(int x)
    20 {
    21     return x!=pre[x]?pre[x]=finde(pre[x]):x;
    22 }
    23 int main()
    24 {
    25     int n,m;
    26     while(scanf("%d%d",&n,&m)!=-1)
    27     {
    28         for(int i=0; i<=n; i++) pre[i]=i;
    29         for(int i=0; i<m; i++) scanf("%d%d%d",&edge[i].x,&edge[i].y,&edge[i].s);
    30         for(int i=m; i<n+m; i++)
    31         {
    32             edge[i].x=0;
    33             edge[i].y=i-m+1;
    34             scanf("%d",&edge[i].s);
    35             if(edge[i].s==-1) edge[i].s=-19999;
    36         }
    37         sort(edge,edge+n+m,cmp);
    38         int ans=0,ans2=0;
    39         for(int i=0; i<n+m; i++)
    40         {
    41             if(edge[i].s==-19999) continue;
    42             int f1=finde(edge[i].x);
    43             int f2=finde(edge[i].y);
    44             if(f1!=f2)
    45             {
    46                 ans+=edge[i].s;
    47                 pre[f1]=f2;
    48             }
    49             else if(edge[i].s<0) ans+=edge[i].s;
    50         }
    51         for(int i=0; i<=n; i++) pre[i]=i;
    52         for(int i=0; i<n+m; i++)
    53         {
    54             if(edge[i].x==0) continue;
    55             int f1=finde(edge[i].x);
    56             int f2=finde(edge[i].y);
    57             if(f1!=f2)
    58             {
    59                 ans2+=edge[i].s;
    60                 pre[f1]=f2;
    61             }
    62             else if(edge[i].s<0) ans2+=edge[i].s;
    63         }
    64         int sum=0;
    65         for(int i=1;i<=n;i++) if(pre[i]==i) sum++;
    66         if(sum!=1) printf("%d
    ",ans);
    67         else printf("%d
    ",min(ans,ans2));
    68     }
    69     return 0;
    70 }
    View Code
  • 相关阅读:
    BZOJ 2034 【2009国家集训队】 最大收益
    vijos P1780 【NOIP2012】 开车旅行
    BZOJ 2115 【WC2011】 Xor
    BZOJ 3631 【JLOI2014】 松鼠的新家
    BZOJ 4717 改装
    BZOJ 2957 楼房重建
    BZOJ 4034 【HAOI2015】 T2
    BZOJ 1834 【ZJOI2010】 network 网络扩容
    BZOJ 2440 【中山市选2011】 完全平方数
    BZOJ 2733 【HNOI2012】 永无乡
  • 原文地址:https://www.cnblogs.com/jeff-wgc/p/4500718.html
Copyright © 2011-2022 走看看