【NOIP2015模拟10.22】最小代价

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
.
.
.
.
.

分析

这里写图片描述
.
.
.
.
.

程序:
#include<iostream>
#include<string.h>
#include<algorithm>
#include<queue>
using namespace std;
struct edge 
{
    long long to,from,v; 
}e[600001],k[600001];
queue<int>q;
int inf=0x3f3f3f;
long long d[100001],ans,fa[100001],n,m,head[100001],c,t;
bool f[100001];

void spfa()
{
    memset(d,inf,sizeof(d));
    memset(f,false,sizeof(f));
    q.push(0); 
    d[0]=0;
    while (!q.empty())
    {
        int u=q.front(); 
        q.pop();
        f[u]=false;
        for (int i=head[u];i;i=e[i].from)
        if (d[u]+e[i].v<d[e[i].to])
        {
            d[e[i].to]=d[u]+e[i].v;
            if (!f[e[i].to])
            {
                q.push(e[i].to);
                f[e[i].to]=true;
            }
        }
    }
}

void dg(int x)
{
    for (long long i=head[x];i;i=e[i].from)
    if (d[x]+e[i].v==d[e[i].to])
    {
        dg(e[i].to);
        k[++t].from=x;k[t].to=e[i].to;k[t].v=e[i].v;
    }
}

long long getfather(int x)
{
    if (fa[x]==x) return x;
    return fa[x]=getfather(fa[x]);
}

void work()
{
    for (int i=1;i<=n;i++) 
    fa[i]=i;
    for (long long i=1;i<=t;i++)
    {
        long long x=getfather(k[i].from),y=getfather(k[i].to);
        if (x!=y)
        {
            ans+=k[i].v;
            fa[y]=x;
        }
    }
}

bool cmp(edge x,edge y) 
{ 
    return x.from<y.from; 
}

void add(int x,int y,int z) 
{ 
    e[++c].to=y; 
    e[c].from=head[x]; 
    e[c].v=z; 
    head[x]=c; 
}

int main()
{
    cin>>n>>m;
    for (int i=1;i<=n;i++)
    {
        int x;
        cin>>x;
        if (x==1) add(0,i,0);
    }
    for (int i=1;i<=m;i++)
    {
        int x,y,z;
        cin>>x>>y>>z;
        add(x,y,z); 
        add(y,x,z);
    }
    spfa();
    dg(0);
    sort(k+1,k+t+1,cmp);
    work();
    if (ans==0) cout<<"impossible"; else cout<<ans;
}
原文地址:https://www.cnblogs.com/YYC-0304/p/9499928.html