题意: 给你一个包含 n 个城市的距离,并告诉你其中的一些路的距离,让你用一些环去覆盖所有点,且每个点只能覆盖一次,问环的最小城市多少。
分析:每个点只出现一次,而每一个点对应一个入的边和一个出的边,可以将入边放入 X 集合, 出边放入 Y 集合,二分该图,求其完全匹配下的最小权值
匹配。


#include<stdio.h> #include<string.h> #define INF 0x1f1f1f #define clr(x)memset(x,0,sizeof(x)) int sx[202],sy[202]; int lx[202],ly[202]; int link[202]; int map[202][202]; int n; int find(int x) { sx[x]=1; int i; for(i=1;i<=n;i++) if(!sy[i]&&lx[x]+ly[i]==map[x][i]) { sy[i]=1; if(link[i]==0||find(link[i])) { link[i]=x; return 1; } } return 0; } int KM() { int sum,i,j,v,dmin; for(i=1;i<=n;i++) { lx[i]=-INF; ly[i]=0; for(j=1;j<=n;j++) if(map[i][j]>lx[i]) lx[i]=map[i][j]; } clr(link); for(v=1;v<=n;v++) while(1) { clr(sx); clr(sy); if(find(v)) break; dmin=INF; for(i=1;i<=n;i++) if(sx[i]) for(j=1;j<=n;j++) if(!sy[j]&&lx[i]+ly[j]-map[i][j]<dmin) dmin=lx[i]+ly[j]-map[i][j]; for(i=1;i<=n;i++) { if(sx[i]) lx[i]-=dmin; if(sy[i]) ly[i]+=dmin; } } sum=0; for(i=1;i<=n;i++) sum+=map[link[i]][i]; return sum; } int main() { int i,j,t,m,a,b,w; scanf("%d",&t); while(t--) { scanf("%d%d",&n,&m); memset(map,-INF,sizeof(map)); while(m--) { scanf("%d%d%d",&a,&b,&w); if(-w>map[a][b]) map[a][b]=-w; } printf("%d\n",-KM()); } return 0; }