zoukankan      html  css  js  c++  java
  • bzoj3624(Apio2008):免费道路

    题目↓

    Sample Input

    5 7 2
    1 3 0
    4 5 1
    3 2 0
    5 3 1
    4 3 0
    1 2 1
    4 2 1

    Sample Output

    3 2 0
    4 3 0
    5 3 1
    1 2 1
     
    芒果君:很明显最小生成树。我一开始的想法有点接近正解(80分),如果一个点连接的边都是0边,而规定的额度k已经用完,就无法再跑kruskal,为了避免这种情况发生,我把这样的点连接的边权值改为-1(使得它们能被优先选)。改题的时候我想到如果一个“0点”连接了很多0边,它就会产生问题——有些与0点连接的点可以被1边更新,却用了0的额度,导致其他的0点无法被更新。
    所以第一遍kruskal只用1边,找出0点(它是当前森林中树的祖宗,不一定只连接了0边,这也补了上面算法漏洞),再根据优先级跑第二遍。无解的判断需要特别注意。
     
     1 #include<cstdio>
     2 #include<cstring>
     3 #include<cmath>
     4 #include<algorithm>
     5 #include<iostream>
     6 #include<ctime>
     7 #include<map>
     8 #define maxn 20010
     9 #define maxm 100010
    10 using namespace std;
    11 struct Edge{
    12     int u,v,w,f;
    13 }e[maxm];
    14 int sign[maxn],fa[maxn],n,m,k,cnt,tot;
    15 bool cmp1(Edge x,Edge y){return x.w>y.w;}
    16 bool cmp2(Edge x,Edge y){return x.w<y.w;}
    17 int find(int x){return x==fa[x]?x:fa[x]=find(fa[x]);}
    18 void kruskal(int f)
    19 {
    20     cnt=0;
    21     for(int i=1;i<=n;++i) fa[i]=i;
    22     for(int i=1;i<=m;++i){
    23         int u=e[i].u,v=e[i].v;
    24         int k1=find(u),k2=find(v);
    25         if(k1!=k2){
    26             if(f){
    27                 if(e[i].w<1){
    28                     if(tot<k) tot++;
    29                     else continue;
    30                 }
    31                 e[i].f=1;
    32             }
    33             else if(!e[i].w) continue;
    34             fa[k1]=k2;
    35             ++cnt;
    36         }
    37         if(cnt+1==n) return;
    38     }
    39 }
    40 int main()
    41 {
    42     scanf("%d%d%d",&n,&m,&k);
    43     for(int i=1;i<=m;++i) scanf("%d%d%d",&e[i].u,&e[i].v,&e[i].w);
    44     sort(e+1,e+m+1,cmp1);
    45     kruskal(0);
    46     cnt=0;
    47     for(int i=1;i<=n;++i){
    48         if(fa[i]==i){
    49             cnt++;
    50             sign[i]=1;
    51         }
    52     }
    53     if(cnt-1>k){
    54         puts("no solution");
    55         return 0;
    56     }
    57     for(int i=1;i<=m;++i) if(!e[i].w) if(sign[e[i].u]||sign[e[i].v]) e[i].w=-1;
    58     sort(e+1,e+m+1,cmp2);
    59     kruskal(1);
    60     if(cnt+1<n||tot!=k){
    61         puts("no solution");
    62         return 0;
    63     }
    64     for(int i=1;i<=m;++i) if(e[i].f) printf("%d %d %d
    ",e[i].u,e[i].v,e[i].w<1?0:1);
    65     return 0;
    66 }
  • 相关阅读:
    FLEX监视浏览器关闭事件
    [FMS]FMS流媒体服务器onStatus介绍说明
    JS调用水晶报表打印翻页按钮事件
    js之获取窗口大小和位置信息
    Window对象简介
    Js中的window.parent ,window.top,window.self 详解
    flex4+fms3.5+cs4开发实时音视频直播及点播详解
    VS2010与水晶报表V13的打包集成小结
    最完美解决方案:js弹出窗口关闭当前页面,而不弹出提示框
    使用C#将HTML文本转换为普通文本,去掉所有的Html标记(转)
  • 原文地址:https://www.cnblogs.com/12mango/p/7641581.html
Copyright © 2011-2022 走看看