• bzoj 3624 免费道路


    题目大意:

    N 个村庄,由 M 条道路连接 其中一些道路是鹅卵石路,而其它道路是水泥路

    求一个方案使保留尽可能少的道路,但是两个不同的村庄之间都应该由一条且仅由一条免费道路的路径连接且刚好保留K条鹅卵石路

    思路:

    并查集

    先将所有水泥路都加入并查集中

    然后找到那些必须被加入的鹅卵石路

    再补上其他的鹅卵石路达到k个

    最后加上其他水泥路

    因为用并查集实现所以最后答案为最小

    (写了三个merge贼辣鸡以及一堆细节见代码

     1 #include<iostream>
     2 #include<cstdio>
     3 #include<cmath>
     4 #include<cstdlib>
     5 #include<cstring>
     6 #include<algorithm>
     7 #include<queue>
     8 #include<vector>
     9 #define ll long long 
    10 #define MAXN 500100
    11 #define inf 2139062143
    12 using namespace std;
    13 inline int read()
    14 {
    15     int x=0,f=1;char ch=getchar();
    16     while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();}
    17     while(isdigit(ch)) {x=x*10+ch-'0';ch=getchar();}
    18     return x*f;
    19 }
    20 int n,m,k,fa[MAXN],sz,cnt;
    21 struct edge {int u,v,c;}e[MAXN];
    22 int find(int x) {return x==fa[x]?x:fa[x]=find(fa[x]);}
    23 //普通合并 
    24 void merge(int a,int b)
    25 {
    26     int x=find(a),y=find(b);
    27     if(x!=y) sz--,fa[x]=y;
    28 }
    29 //带输出及填k个鹅卵石路合并 
    30 void Merge(int a,int b,int &z)
    31 {
    32     int x=find(a),y=find(b);
    33     if(x==y) return ;
    34     if(!z&&k>0) {fa[x]=y,k--;printf("%d %d %d
    ",a,b,z);z=1;}
    35     else if(z) {fa[x]=y;printf("%d %d %d
    ",a,b,z);}
    36 }
    37 //记录需要的鹅卵石路及填k个鹅卵石路合并 
    38 void MergE(int a,int b,int &z)
    39 {
    40     int x=find(a),y=find(b);
    41     if(x==y||k==0) return ;
    42     fa[x]=y,k--,z=-1,sz--;
    43 }
    44 int main()
    45 {
    46     n=read(),m=read(),k=read(),sz=n;
    47     for(int i=1;i<=n;i++) fa[i]=i;
    48     for(int i=1;i<=m;i++) {e[i].u=read(),e[i].v=read(),e[i].c=read(),cnt+=e[i].c;merge(e[i].u,e[i].v);}
    49     if(m-cnt<k||sz>1||n==1) {puts("no solution");return 0;}//鹅卵石路不够k个或者所有路都无法把所有点联通 
    50     for(int i=1;i<=n;i++) fa[i]=i;sz=n;
    51     for(int i=1;i<=m;i++) if(e[i].c) merge(e[i].u,e[i].v);
    52     //求出必须的鹅卵石路 
    53     for(int i=1;i<=m;i++)
    54         if(!e[i].c) MergE(e[i].u,e[i].v,e[i].c);
    55     if(sz>1) {puts("no solution");return 0;}//必须的鹅卵石路比k个多
    56     for(int i=1;i<=n;i++) fa[i]=i;
    57     for(int i=1;i<=m;i++)
    58         if(e[i].c<0) merge(e[i].u,e[i].v);
    59     //求出其他鹅卵石路 
    60     for(int i=1;i<=m;i++)
    61         if(!e[i].c) MergE(e[i].u,e[i].v,e[i].c);
    62     if(k) {puts("no solution");return 0;}//鹅卵石路形成的无环图达不到k个 
    63     for(int i=1;i<=m;i++) 
    64         if(e[i].c<0) printf("%d %d 0
    ",e[i].u,e[i].v);
    65     for(int i=1;i<=m;i++)
    66         if(e[i].c>0) Merge(e[i].u,e[i].v,e[i].c);
    67 }
    View Code
  • 相关阅读:
    c#查找窗口的两种办法
    也说自动化测试
    定位bug的基本要求
    c#调用GetModuleFileNameEx获取进程路径
    对比PG数据库结构是否一致的方法
    C#调用endtask
    提bug
    接口测试的结果校验
    ProcessExplorer使用分享
    C++如何在r3静态调用NT函数
  • 原文地址:https://www.cnblogs.com/yyc-jack-0920/p/8987880.html
Copyright © 2020-2023  润新知