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

题目描述:
给出一幅由 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]to[i]])
  dis[to[i]]=dis[a]+val[i];

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

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

#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
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//---------------------
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]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"<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<return 0;
}

你可能感兴趣的:(考试总结)