HDU 3435 A new Graph Game

题意:删除一些边得到一个或多个哈密尔顿图,使得所有边权之和最小

分析:双向边赋值,取反求最大匹配并判断是否是完全匹配


#include <iostream>
#include<cstdio>
#include<string>
#include<algorithm>
#include<cstring>
#include<queue>
#define INF 60001
#define N 1005
using namespace std;
int nx,ny,lx[N],ly[N],link[N],slack[N],visx[N],visy[N],w[N][N];
bool DFS(int x){
    int y;
    visx[x]=1;
    for(y=1;y<=ny;y++){
        if(!visy[y]){
            int t=lx[x]+ly[y]-w[x][y];
            if(t==0){
                visy[y]=1;
                if(link[y]==-1||DFS(link[y])){
                    link[y]=x;
                    return true;
                }
            }else if(slack[y]>t){
                slack[y]=t;
            }
        }
    }
    return false;
}
int KM(){
    int i,j,x;
    memset(link,-1,sizeof(link));
    memset(ly,0,sizeof(ly));
    for(i=1;i<=nx;i++){
        for(j=1,lx[i]=-INF;j<=ny;j++)
        if(w[i][j]>lx[i])
        lx[i]=w[i][j];
    }
    for(x=1;x<=nx;x++){
        for(i=1;i<=ny;i++)
        slack[i]=INF;
        while(1){
            memset(visx,0,sizeof(visx));
            memset(visy,0,sizeof(visy));
            if(DFS(x))
            break;
            int d=INF;
            for(i=1;i<=ny;i++)
                if(!visy[i]&&d>slack[i])
                d=slack[i];
            for(i=1;i<=nx;i++)
                if(visx[i])
                lx[i]-=d;
            for(i=1;i<=ny;i++){
                if(visy[i])
                ly[i]+=d;
                else
                slack[i]-=d;
            }
        }
    }
    int ans=0;
    for(i=1;i<=ny;i++){
       if(link[i]==-1||w[link[i]][i]==-INF)
            return -1;
            ans+=w[link[i]][i];
    }
    return -ans;
}
int main()
{
    int T,s,t,i,j,k,ans,n,m,ics=0;
    scanf("%d",&T);
    while(T--){
        scanf("%d%d",&n,&m);
        nx=ny=n;
        for(i=1;i<=n;i++){
            for(j=1;j<=n;j++)
            w[i][j]=-INF;
        }
        while(m--){
            scanf("%d%d%d",&i,&j,&k);
            w[i][j]=max(w[i][j],-k);
            w[j][i]=w[i][j];
        }
        ans=KM();
        printf("Case %d: ",++ics);
        if(ans==-1)
        printf("NO\n");
        else
        printf("%d\n",ans);
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值