vijos1070 新年趣事

http://www.elijahqi.win/archives/1038
描述

xiaomengxian的哥哥是一个游戏迷,他喜欢研究各种游戏。这天,xiaomengxian到他家玩,他便拿出了自己最近正在研究的一个游戏给xiaomengxian看。这个游戏是这样的:一个国家有N个城市,有些城市之间可以建设铁路,并且不同城市之间建设铁路的费用各不相同。问如何用最小的费用,使整个国家的各个城市之间能够互相到达。另外,铁路是双向的。xiaomengxian心想,这不是太简单了吗?这就是经典的MST问题。他的哥哥说,这个当然不算什么。关键是它还要求费用第二小的方案,这真是让人伤脑筋。xiaomengxian想了很久,也没有想出来,你能帮助他吗?
费用第二小的方案的定义为:与费用最小的方案不完全相同,且费用值除费用最小的方案外最小。

格式

输入格式

第一行两个数N(2<=N<=500),M,分别表示国家的城市数和可以修建铁路的城市有多少对。

接下来M行,每行三个正整数Ai,Bi,Ci,表示城市Ai和Bi之间可以修建铁路,费用为Ci。

输出格式

第一行:”Cost: “+一个整数,表示最小费用。(若不存在,输出-1)
第二行:”Cost: “+一个整数,表示第二小费用。(若不存在,输出-1)

样例1

样例输入1

4 6
1 2 2
2 3 2
3 4 2
4 1 2
1 3 1
2 4 1
Copy
样例输出1

Cost: 4
Cost: 4
Copy
限制

各个测试点1s

提示

Sample input #2
3 2
1 2 2
2 3 2

Sample output #2
Cost: 4
Cost: -1

次小生成树 :思路就是我们先建立一棵最小生成树

然后枚举非树边 然后把两个端点树上路径的最大值找出来,求出最大值和非树边权值差 找到权值差最小即可

#include<cstdio>
#include<algorithm>
#include<cstring>
#define N 550
using namespace std;
inline int read(){
    int x=0,f=1;char ch=getchar();
    while (ch<'0'||ch>'9') {
        if (ch=='-') f=-1;ch=getchar();
    }
    while (ch<='9'&&ch>='0'){x=x*10+ch-'0';ch=getchar();}
    return x*f;
}
struct node{
    int x,y,z,next;
}data[N*N],data1[N<<1];
int fa1[N],m,n,h[N],fa[N][20],st[N][20],dep[N],qq,Log[N];bool visit[N*N];
inline bool cmp(node a,node b){return a.z<b.z;}
inline int find(int x){return x==fa1[x]?x:fa1[x]=find(fa1[x]);}
void dfs1(int x){
    for (int i=h[x];i;i=data1[i].next){
        int y=data1[i].y;
        if (fa[x][0]==y) continue;
        dep[y]=dep[x]+1;st[y][0]=data1[i].z;fa[y][0]=x;
        for (int j=1;j<=Log[dep[y]-1];++j){
            fa[y][j]=fa[fa[y][j-1]][j-1];st[y][j]=max(st[y][j-1],st[fa[y][j-1]][j-1]);
        }
        dfs1(y);
    }
}
inline int lca(int x,int y){
    int min1=0;
    if (dep[x]!=dep[y]){
        if (dep[x]<dep[y]) swap(x,y);
        int lg=Log[dep[x]-dep[y]];
        for (int j=0;j<=lg;++j){
            if ((1<<j)&(dep[x]-dep[y])) {
                min1=max(min1,st[x][j]);x=fa[x][j];
            }
        }
    }
    if (x==y) return min1;
    for (int j=19;j>=0;--j){
        if (fa[x][j]!=fa[y][j]){
            min1=max(min1,st[x][j]);min1=max(min1,st[y][j]);x=fa[x][j];y=fa[y][j];
        }
    }
    return max(min1,max(st[x][0],st[y][0]));
}
int main(){
    freopen("vijos1070.in","r",stdin);
    n=read();m=read();
    for (int i=1;i<=m;++i){
        int x=read(),y=read(),z=read();
        data[i].x=x;data[i].y=y;data[i].z=z;
    }
    sort(data+1,data+m+1,cmp);
    for (int i=1;i<=n;++i) fa1[i]=i;int cnt=0,num=0,ans=0;
    for (int i=1;i<=m;++i){
        int x=data[i].x,y=data[i].y,z=data[i].z;
        int xx=find(x),yy=find(y);
        if (xx!=yy){
            ++cnt;data1[++num].y=y;data1[num].z=data[i].z;data1[num].next=h[x];h[x]=num;data1[num].x=x;
            data1[++num].y=x;data1[num].z=data[i].z;data1[num].next=h[y];h[y]=num;fa1[xx]=yy;data1[num].x=y;
            visit[i]=true;ans+=z;
            if (cnt==n-1) break;
        }
    }   //for (int i=1;i<=num;++i) printf("%d %d %d\n",data1[i].x,data1[i].y,data1[i].z);printf("asdfasd\n");
//  if (cnt<n-1) {printf("Cost: -1\nCost: -1");return 0;}
    printf("Cost: %d\n",ans);
    Log[0]=-1;
    for (int i=1;i<=n;++i) Log[i]=Log[i>>1]+1;
    dep[1]=1;dfs1(1);bool flag=false;int ans1=0x7f7f7f7f;
    for (int i=1;i<=m;++i){
        if (!visit[i]){
            int x=data[i].x,y=data[i].y,z=data[i].z;
            int max1=lca(x,y);
            if (z-max1<ans1) ans1=min(ans1,z-max1),flag=true;
        }
    }
    if (flag) printf("Cost: %d",ans+ans1);else printf("Cost: -1");
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值