cogs 1578. 次小生成树初级练习题

1578. 次小生成树初级练习题

☆   输入文件:mst2.in   输出文件:mst2.out   简单对比
时间限制:1 s   内存限制:256 MB

【题目描述】

求严格次小生成树

【输入格式】

第一行包含两个整数N 和M,表示无向图的点数与边数。 接下来 M行,每行 3个数x y z 表示,点 x 和点y之间有一条边,边的权值为z。

【输出格式】

包含一行,仅一个数,表示严格次小生成树的边权和。(数据保证必定存在严格次小生成树)

【样例输入】

5 6

1 2 1

1 3 2

2 4 3

3 5 4

3 4 3

4 5 6

【样例输出】

11

【提示】

数据中无向图无自环; 50% 的数据N≤2 000 M≤3 000; 80% 的数据N≤50 000 M≤100 000; 100% 的数据N≤100 000 M≤300 000 ,边权值非负且不超过 10^9 。

【来源】

bzoj。。。

思路:吐槽这个题目,数据太水了。就是先跑一边最小生成树,记录下跑时经过的边,然后枚举删边,继续跑次小生成树。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
struct nond{
    int x,y,z;
}edge[400000];
int T,N,M,x,y,z,fa[200000],num,ans[200000];
int tot,bns,k,answer=0x7f7f7f7f;
int cmp(nond aa,nond bb){
    return aa.z<bb.z;
}
int find(int x){
    return fa[x]==x?x:fa[x]=find(fa[x]);
}
int main(){
    freopen("mst2.in","r",stdin);
    freopen("mst2.out","w",stdout);
    cin>>N>>M;
    for(int i=1;i<=M;i++){
        cin>>x>>y>>z;
        edge[i].x=x;
        edge[i].y=y;
        edge[i].z=z;
    }
    sort(edge+1,edge+1+M,cmp);
    for(int i=1;i<=N;i++)    fa[i]=i;
    for(int i=1;i<=M;i++){
        int dx=find(edge[i].x);
        int dy=find(edge[i].y);
        if(dx!=dy){
            fa[dx]=dy;
            tot++;
            ans[tot]=i;
            bns+=edge[i].z;
        }
        if(tot==N-1)    break;
    }
    for(int i=1;i<=tot;i++){
        k=0;num=0;
        for(int j=1;j<=N;j++)    fa[j]=j;
        sort(edge+1,edge+1+M,cmp);
        for(int j=1;j<=M;j++){
            if(j==ans[i])    continue;
            int dx=find(edge[j].x);
            int dy=find(edge[j].y);
            if(dx!=dy){
                fa[dx]=dy;
                num++;
                k+=edge[j].z;
            }
            if(num==N-1)    break;
        }
        if(num==N-1&&k!=bns) answer=min(k,answer);
    }
    cout<<answer;
}

 

posted @ 2017-08-23 10:15  一蓑烟雨任生平  阅读(147)  评论(2编辑  收藏  举报