题意:删除一些边得到一个或多个哈密尔顿图,使得所有边权之和最小
分析:双向边赋值,取反求最大匹配并判断是否是完全匹配
#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;
}