进阶指南的板子好像有点问题。。交到hdu上会T
需要了解的一些概念:
交错树,顶标,修改量
#include<iostream> #include<stdio.h> #include<string.h> #include<algorithm> using namespace std; #define INF 99999999 #define maxn 305 int lx[maxn],ly[maxn];//顶标 int Match[maxn];//记录匹配值 int visx[maxn],visy[maxn]; int w[maxn][maxn];//权值 int slack[maxn];//slack为修改量 int ans,n; bool findPath(int x){ visx[x]=1; for(int y=1; y<=n; y++){ if(visy[y])continue; if(w[x][y]==lx[x]+ly[y]){//如果是相等子图则加入交错树中 visy[y]=1; if(!Match[y]||findPath(Match[y])){//增广后不用再考虑交错树 Match[y]=x; return true; } } else//不能加入交错树中的点,用来更新修改量 slack[y]=min(slack[y],lx[x]+ly[y]-w[x][y]); } return false; } void km(){ memset(Match,0,sizeof(Match)); memset(lx,0,sizeof(lx)); memset(ly,0,sizeof(ly)); for(int i=1; i<=n; i++) for(int j=1; j<=n; j++) lx[i]=max(lx[i],w[i][j]); for(int x=1; x<=n; x++){ for(int i=1;i<=n;i++)slack[i]=INF;//初始化修改量 while(1){ memset(visx,0,sizeof(visx)); memset(visy,0,sizeof(visy)); if(findPath(x))break;//直到x找到一个匹配点时退出循环 //如果没找到匹配点(增广失败),那么找最小修改量, int tmp=INF; for(int i=1;i<=n;i++){ if(!visy[i]){ if(tmp>slack[i]) tmp=slack[i]; } } //更新交错树中的顶标 for(int i=1; i<=n; i++){ if(visx[i]) lx[i]-=tmp; if(visy[i]) ly[i]+=tmp;else slack[i]-=tmp; } } } } int main(){ while(scanf("%d",&n)!=EOF){ ans=0; for(int i=1; i<=n; i++) for(int j=1; j<=n; j++) scanf("%d",&w[i][j]); km(); for(int i=1; i<=n; i++) ans+=w[Match[i]][i]; printf("%d\n",ans); } return 0; }
#include<iostream> #include<algorithm> #include<cstdio> #include<cstring> #include<cmath> using namespace std; const int MAXN = 110; const double INF = 0xffffffffffff; const double eps = 1e-6; struct Node { double x,y; }Dot1[MAXN],Dot2[MAXN]; double Dist(Node a,Node b) { return -sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y)); } int N,NX,NY; double Map[MAXN][MAXN]; int link[MAXN]; double lx[MAXN],ly[MAXN],slack[MAXN]; int visx[MAXN],visy[MAXN]; int FindPath(int u) { visx[u] = 1; for(int i = 1; i <= NY; ++i) { if(visy[i]) continue; double temp = lx[u] + ly[i] - Map[u][i]; if(fabs(temp) <= eps) { visy[i] = 1; if(link[i] == -1 || FindPath(link[i])) { link[i] = u; return 1; } } else { if(slack[i] > temp) slack[i] = temp; } } return 0; } void KM() { memset(lx,0,sizeof(lx)); memset(ly,0,sizeof(ly)); memset(link,-1,sizeof(link)); for(int i = 1; i <= NX; ++i) { lx[i] = -INF; for(int j = 1; j <= NY; ++j) if(Map[i][j] > lx[i]) lx[i] = Map[i][j]; } for(int i = 1; i <= NX; ++i) { for(int j = 1; j <= NY; ++j) slack[j] = INF; while(1) { memset(visx,0,sizeof(visx)); memset(visy,0,sizeof(visy)); if(FindPath(i)) break; double d = INF; for(int j = 1; j <= NY; ++j) if(!visy[j] && d > slack[j]) d = slack[j]; for(int j = 1; j <= NX; ++j) if(visx[j]) lx[j] -= d; for(int j = 1; j <= NY; ++j) { if(visy[j]) ly[j] += d; else slack[j] -= d; } } } } int main() { int N; while(~scanf("%d",&N)) { memset(Map,0,sizeof(Map)); for(int i = 1; i <= N; ++i) scanf("%lf%lf",&Dot1[i].x,&Dot1[i].y); for(int i = 1; i <= N; ++i) scanf("%lf%lf",&Dot2[i].x,&Dot2[i].y); for(int i = 1; i <= N; ++i) for(int j = 1; j <= N; ++j) Map[i][j] = Dist(Dot1[i],Dot2[j]); NX = NY = N; KM(); for(int i = 1; i <= N; ++i) { for(int j = 1; j <= N; ++j) { if(link[j] == i) { printf("%d\n",j); break; } } } } return 0; }