zoukankan      html  css  js  c++  java
  • [spfa][最小生成树] Jzoj P4261 最小代价

    Description

    给出一幅由n个点m条边构成的无向带权图。
    其中有些点是黑点,其他点是白点。
    现在每个白点都要与他距离最近的黑点通过最短路连接(如果有很多个黑点,可以选取其中任意一个),我们想要使得花费的代价最小。请问这个最小代价是多少?
    注意:最后选出的边保证每个白点到离它最近的黑点的距离仍然等于原图中的最短距离。
     

    Input

    第一行两个整数n,m;
    第二行n 个整数,0表示白点,1 表示黑点;
    接下来m 行,每行三个整数x,y,z,表示一条连接x和y 点,权值为z 的边。

    Output

    如果无解,输出impossible;
    否则,输出最小代价。
     

    Sample Input

    5 7
    0 1 0 1 0
    1 2 11
    1 3 1
    1 5 17
    2 3 1
    3 5 18
    4 5 3
    2 4 5

    Sample Output

    5
    【样例解释】
    选 2、4、6三条边
     

    Data Constraint

    对30%的输入数据: 1≤n≤10, 1≤m≤20;
    对100%的输入数据:1≤n≤100000,1≤m≤200000,1≤z≤1000000000

    题解

    • 一开始时,一直在想如果找到与哪个黑点相连
    • 可以考虑一下从建一个S源点,然后把黑点向S点连一条权值为0的边
    • 然后我们就可以求出从S点到所有点的最短距离
    • 问题就转换为了求白点到S的距离
    • 从S出发往回dfs,找到最短路径上的边
    • 一条边可能被多次经过,我们dfs可能会重复把边选出来,但题目要求一条边只加一次代价
    • 所以可以用Kruskal,把边连起来,避免重复边
    • 如果我们求的边权和ans==0,那么说明一条边也找不到,那么“impossible”

    代码

     1 #include<cstdio>
     2 #include<iostream>
     3 #include<cstring>
     4 #include<cmath>
     5 #include<algorithm>
     6 #include<queue>
     7 using namespace std;
     8 const int inf=0x3f3f3f;
     9 struct edge {long long to,from,v; }e[300010*2],k[300010*2];
    10 long long dis[100010],ans,fa[100010],n,m,head[100010],cnt,tot;
    11 bool f[100010];
    12 queue<int>Q;
    13 void insert(int x,int y,int z) { e[++cnt].to=y; e[cnt].from=head[x]; e[cnt].v=z; head[x]=cnt; }
    14 void spfa()
    15 {
    16     memset(dis,inf,sizeof(dis));
    17     memset(f,false,sizeof(f));
    18     Q.push(0); dis[0]=0;
    19     while (!Q.empty())
    20     {
    21         int u=Q.front(); Q.pop();
    22         f[u]=false;
    23         for (int i=head[u];i;i=e[i].from)
    24             if (dis[u]+e[i].v<dis[e[i].to])
    25             {
    26                 dis[e[i].to]=dis[u]+e[i].v;
    27                 if (!f[e[i].to])
    28                 {
    29                     Q.push(e[i].to);
    30                     f[e[i].to]=true;
    31                 }
    32             }
    33     }
    34 }
    35 void dg(int x)
    36 {
    37     for (long long i=head[x];i;i=e[i].from)
    38         if (dis[x]+e[i].v==dis[e[i].to])
    39         {
    40             dg(e[i].to);
    41             k[++tot].from=x,k[tot].to=e[i].to,k[tot].v=e[i].v;
    42         }
    43 }
    44 long long getfather(int x)
    45 {
    46     if (fa[x]==x) return x;
    47     return fa[x]=getfather(fa[x]);
    48 }
    49 void kruskal()
    50 {
    51     for (long long i=1;i<=tot;i++)
    52     {
    53         long long x=getfather(k[i].from),y=getfather(k[i].to);
    54         if (x!=y)
    55         {
    56             ans+=k[i].v;
    57             fa[y]=x;
    58         }
    59     }
    60 }
    61 bool cmp(edge x,edge y) { return x.from<y.from; }
    62 int main()
    63 {
    64     scanf("%lld%lld",&n,&m);
    65     for (int i=1;i<=n;i++)
    66     {
    67         int x;
    68         scanf("%d",&x);
    69         if (x==1) insert(0,i,0);
    70     }
    71     for (int i=1;i<=m;i++)
    72     {
    73         int x,y,z;
    74         scanf("%d%d%d",&x,&y,&z);
    75         insert(x,y,z); insert(y,x,z);
    76     }
    77     spfa();
    78     dg(0);
    79     sort(k+1,k+tot+1,cmp);
    80     for (int i=1;i<=n;i++) fa[i]=i;
    81     kruskal();
    82     if (ans==0) printf("impossible"); else printf("%lld",ans);
    83 }
  • 相关阅读:
    MyOD-Linux od命令的实现
    20175320 2018-2019-2 《Java程序设计》第9周学习总结
    MyCP-实现文件的复制以及进制转换
    20175320 2018-2019-2 《Java程序设计》第8周学习总结
    2018-2019-2 20175320实验二《Java面向对象程序设计》实验报告
    20175320 2018-2019-2 《Java程序设计》第7周学习总结
    类定义20175320
    20175320 2018-2019-2 《Java程序设计》第6周学习总结
    结对编程项目-四则运算阶段性总结
    算法复习周------递归之“合并排序”
  • 原文地址:https://www.cnblogs.com/Comfortable/p/9296326.html
Copyright © 2011-2022 走看看