NOIP2017 7.17模拟 Minimum (最短路+最小生成树)

来源:互联网 发布:凸的网络意思是什么 编辑:程序博客网 时间:2024/06/16 07:24

题目描述:
给出一幅由 n 个点 m 条边构成的无向带权图。
其中有些点是黑点,另外点是白点。
现在每个白点都要与他距离最近的黑点通过最短路连接(如果有很多个,连所有的),我们想要使得花费的代价最小。请问这个最小代价是多少?
注意:最后选出的边保证每个白点到黑点的距离任然是最短距离。(这句话题解代码也无法实现,就不管了)

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

输出:
如果无解,输出“impossible”,否则,输出最小代价。

样例数据:
输入
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
输出
5

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

题意:将所有白点和黑点通过在最短路上的路径连接,求最小代价,无解的情况是存在白点与黑点无法连通。通过分析我们可以发现,有解的情况可以分为两个问题考虑:
1、求最短路;
2.并找到在最短路上的边;
3、通过这些边跑一边最小生成树,统计边权之和。

对于第一个问题,因为是要求任意一个白点到任意一个黑点的距离,我们可以想到建一个超级点,由它向每一个黑点连一条边权为0的有向边,然后由这个超级点跑一次最短路(迪杰斯特拉或spfa),就行了;

对于第二个问题,由最短路的更新方法

if(dis[a]+val[i]<dis[to[i]])  dis[to[i]]=dis[a]+val[i];

我们可以想到,遍历每条边,满足dis[edge[i].start]==dis[edge[i].end+edge[i[.val那么这条边一定是最短路上的边,由此我们可以找到所有最短路上的边

对于第三个问题,裸的最小生成树,在此就不赘述了;

#include<cstdio>#include<cstdlib>#include<algorithm>#include<cmath>#include<ctime>#include<cstring>#include<string>#include<iomanip>#include<iostream>#include<cctype>#include<queue>using namespace std;int n,m,tot,sup,cnt,len,fa[100005],next[500010],first[100005],to[500010];long long dis[100005];long long val[500010];bool black[100005],ok=true;//---------------------priority_queue< pair<int,int> > que;pair<int,int> temp;//---------------------struct node{    int st,end;    long long val;}a[400010];bool cmp(const node&a,const node&b){    return a.val<b.val;}//---------------------inline long long Readint(){    long long i=0,f=1;    char ch;    for(ch=getchar();(ch<'0'||ch>'9')&&ch!='-';ch=getchar());    if(ch=='-') f=-1;    for(;ch>='0'&&ch<='9';ch=getchar()) i=(i<<1)+(i<<3)+ch-'0';    return i*f;}//---------------------inline void add(int x,int y,long long z){    next[++tot]=first[x];    first[x]=tot;    to[tot]=y;    val[tot]=z;}//---------------------inline void djstra(int root){    dis[root]=0;    temp.first=0;    temp.second=root;    que.push(temp);    while(!que.empty()){        temp=que.top();        que.pop();        int a=temp.second;        for(int i=first[a];i;i=next[i]){            if(dis[a]+val[i]<dis[to[i]]){                dis[to[i]]=dis[a]+val[i];                    pair<int,int> s;                    s.first=-dis[to[i]];                    s.second=to[i];                    que.push(s);            }        }    }}//---------------------inline int find(int x){    if(x==fa[x]) return x;    fa[x]=find(fa[x]);    return fa[x];}//---------------------int main(){    freopen("minimum.in","r",stdin);    n=Readint(),m=Readint();    memset(first,0,sizeof(first));    for(int i=0;i<=n;i++) fa[i]=i;    for(int i=0;i<=n;i++) dis[i]=1e16+7;    for(int i=1;i<=n;i++){        black[i]=Readint();        if(black[i]) add(sup,i,0);    }     for(int i=1;i<=m;i++){        int x,y;        long long z;        x=Readint(),y=Readint(),z=Readint();        add(x,y,z),add(y,x,z);    }    djstra(sup);    for(int i=1;i<=n;i++) if(dis[i]==1e16+7) ok=false;    if(!ok){        cout<<"impossible"<<endl;        return 0;    }    for(int i=1;i<=n;i++){        for(int p=first[i];p;p=next[p]){            if(dis[to[p]]==val[p]+dis[i]){                a[++len].st=i,a[len].end=to[p],a[len].val=val[p];            }        }    }    long long ans=0;    sort(a+1,a+1+len,cmp);    for(int i=1;i<=len;i++){        int fx=find(a[i].st),fy=find(a[i].end);        if(fx!=fy){            fa[fx]=fy;            ans+=a[i].val;            cnt++;        }        if(cnt==n-1) break;    }    cout<<ans<<endl;    return 0;}
原创粉丝点击