UVA 10600 - ACM Contest and Blackout (次小生成树)

49 篇文章 0 订阅

/* 次小生成树的问题,  方法:求出最小生成树 并且标记路径   F[i][j] 代表最小生成树中i->j中最大的一条边  如果map(i,j)> F[i][j]

则替换这条边  枚举每一条不在最小生成树中的边  替换之 找出最小的。

*/


#include<cstdio>

#include<cstring>
#define INF 1<<30
int map[110][110],n,m;
int vis[110],use[110][110],low[110];
int pre[110],F[110][110];
int max(int x,int y)
{
    return x>y?x:y;
}
int prim(int s,int t)
{
    int ans=0;
    memset(pre,-1,sizeof(pre));
    pre[s] = -1;
    memset(F,0,sizeof(F));
    for(int i = 1; i <= n; i++)
    {
        vis[i] = 0;
        low[i] = INF;
    }
    low[1] = 0;
    //vis[s] = 1;
    for(int i = 1; i <= n; i++)
    {
        int temp = INF,tp=-1;
        for(int j = 1; j <= n; j++)
            if(!vis[j]&&temp>low[j])
            {
                tp = j;
                temp=low[j];
            }
        if(tp==-1) continue;
        int k = tp;
        int v = pre[k];
        if(v!=-1)
        {
            use[k][v]=use[v][k]=2;
            for(int j = 1; j <= n; j++)
                if(vis[j])
                    F[j][k] = max(F[j][v],map[v][k]);
        }
        vis[k] = 1;
        ans+=low[k];
        for(int j = 1; j <= n; j++)
            if(!vis[j]&&low[j]>map[k][j])
            {
                low[j] = map[k][j];
                pre[j] = k;
            }
    }
    return ans;
}
int second_mst(int x)
{
    int res=x,ans=INF;
    for(int i = 1; i <= n; i++)
    for(int j = 1; j <= n; j++)
    if(use[i][j]==1&&map[i][j]!=INF&&F[i][j]!=INF)
    {
        if(res+map[i][j]-F[i][j] < ans)
        ans = res+map[i][j]-F[i][j];
        //printf("%d.%d.\n",F[i][j],map[i][j]);
    }
    return ans;
}
int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d%d",&n,&m);
        for(int i = 0; i<=n; i++)
            for(int j = 0; j<=n; j++)
                map[i][j] = INF;
        memset(use,0,sizeof(use));
        int x,y,z;
        for(int i = 0; i < m; i++)
        {
            scanf("%d%d%d",&x,&y,&z);
            map[x][y]=map[y][x]=z;
            use[x][y]=use[y][x]=1;
        }
        int ans=prim(1,n);
        int ans1=second_mst(ans);
        printf("%d %d\n",ans,ans1);
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值