【JZOJ B组】【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

思路

对于每一个黑点,我们向原点s连一条权值为0的边,然后求s到各点的最短路。可以发现每条路只会经过一个黑点。

跑完最短路,我们可以得到一个最短路图。

现在,我们需要每一个点联通,跑一个mintree即可

代码

#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
#include<algorithm>
using namespace std;
const int maxn=500077,inf=0x3f3f3f3f;
struct E
{
    long long to,next,v;
}e[maxn*2];
struct P
{
    long long num,val;
}pre[maxn];
struct A
{
    long long x,y,v;
}a[maxn*2];
long long n,m,cnt=0,list[maxn],f[maxn],d[maxn],s,ass=0;
bool b[maxn];
int cmp(A x,A y)
{
    return x.v<y.v;
}
void add(int u,int v,long long val)
{
    e[++cnt].to=v; e[cnt].next=list[u]; e[cnt].v=val; list[u]=cnt;
}
void spfa()
{
    queue<int> q;
    memset(b,0,sizeof(b));
    q.push(s); d[s]=0; 
    while(!q.empty())
    {
        int u=q.front(); q.pop();
        for(int i=list[u]; i; i=e[i].next)
        {
            if(d[u]+e[i].v<d[e[i].to])
            {
                d[e[i].to]=d[u]+e[i].v;
                if(!b[e[i].to]) q.push(e[i].to),b[e[i].to]=1;
                pre[e[i].to].num=u,pre[e[i].to].val=e[i].v;
            }
        }
        b[u]=0;
    }
}
void get_edge(int x)
{
    while(x!=s)
    {
        a[++cnt].x=x; a[cnt].y=pre[x].num; a[cnt].v=pre[x].val;
        x=pre[x].num;
    }
}
int gf(int x)
{
    if(f[x]!=x) f[x]=gf(f[x]);
    return f[x];
}
void mintree()
{
    int ss=0;
    for(int i=1; i<=n+1; i++) f[i]=i;
    for(int i=1; i<=cnt; i++)
    {
        int u=gf(a[i].x),v=gf(a[i].y);
        if(u!=v)
        {
            ass+=a[i].v; ss++;
            f[u]=v;
        }
    }
    if (ass==0||ss<n) printf("impossible");
    else printf("%lld\n",ass);
}
int main()
{
//  freopen("minimum8.in","r",stdin);
    scanf("%d%d",&n,&m);
    s=n+1;
    bool bb=0;
    for(int i=1; i<=n; i++)
    {
        int x;
        scanf("%d",&x);
        if(x==1) add(s,i,0),add(i,s,0),bb=1;
    }
    if(!bb) 
    {
        printf("impossible");
        return 0;
    }
    for(int i=1; i<=m; i++)
    {
        int x,y,v;
        scanf("%d%d%d",&x,&y,&v);
        add(x,y,v); add(y,x,v);
    }
    memset(d,63,sizeof(d));
    spfa();
//  memset(e,0,sizeof(e)); 
    cnt=0;
    for(int i=1; i<=n; i++) get_edge(i);
    sort(a+1,a+cnt+1,cmp);
    mintree();
}

猜你喜欢

转载自blog.csdn.net/eric1561759334/article/details/81005614
今日推荐