km算法在百度上讲的很清楚
讲一些针对这道题的
有n只蚂蚁要吃n个苹果,求总路径和最小,且不交叉的方案
网上有很多人说是计算几何题
其实,研究一下题意可以得出很重要的性质————最优方案一定不交叉。
根据三角形不等式
ad+bc<ac+bd dc+ab<ac+bd
因此,我们只需要构造二分图,求最小权和匹配
将所有蚂蚁看做一个集合,所有苹果看做一个集合,求出各蚂蚁到各苹果的距离并取反,在这个二分图上用km算法
容易发现这个模型是完全二分图,因此,加上slack优化可以快很多(在其他情况下slack优化优化为O(n^3),不过也有人说只优化常数)。
这道题的相等判断要注意精度,否则会死循环。
const eps=1e-6; var lx,ly,slack:array[1..100]of real; x1,x2,y1,y2:array[1..100]of longint; vx,vy:array[1..100]of boolean; cost:array[1..100,1..100]of real; b,c:array[1..100]of longint; n:longint; function km(x:longint):boolean; var i:longint; tmp:real; begin if vx[x] then exit(false); vx[x]:=true; for i:=1 to n do begin tmp:=lx[x]+ly[i]-cost[x,i]; if not(vy[i])and(tmp<eps) then begin vy[i]:=true; if (b[i]=0)or(km(b[i])) then begin b[i]:=x;c[x]:=i; exit(true) end end else if tmp<slack[i] then slack[i]:=tmp end; exit(false) end; procedure init; var i,j,k:longint; d:real; begin readln(n); for i:=1 to n do readln(x1[i],y1[i]); for i:=1 to n do readln(x2[i],y2[i]); fillchar(ly,sizeof(ly),0); for i:=1 to n do lx[i]:=-maxlongint; for i:=1 to n do for j:=1 to n do begin cost[i,j]:=-sqrt(sqr(x1[i]-x2[j])+sqr(y1[i]-y2[j])); if cost[i,j]>lx[i] then lx[i]:=cost[i,j] end; fillchar(b,sizeof(b),0); for i:=1 to n do begin fillchar(vx,sizeof(vx),false); fillchar(vy,sizeof(vy),false); fillchar(slack,sizeof(slack),127); while not(km(i)) do begin d:=maxlongint; for k:=1 to n do if not(vy[k]) then if slack[k]<d then d:=slack[k]; for j:=1 to n do begin if vx[j] then lx[j]:=lx[j]-d; if vy[j] then ly[j]:=ly[j]+d else slack[j]:=slack[j]-d end; fillchar(vx,sizeof(vx),false); fillchar(vy,sizeof(vy),false); fillchar(slack,sizeof(slack),127) end end; for i:=1 to n do writeln(c[i]) end; begin assign(input,'3565.in');reset(input); init; close(input) end.
#include <cstdio> #include <cstdlib> #include <cstdlib> #include <cstring> #include <iostream> #include <algorithm> const long long oo=(1LL<<50); using namespace std; struct point{ int x,y; point() {} point(int X,int Y) { x=X,y=Y; } }p[2][2000]; long long c[1000][1000]; int b1[1000],u[1000]; long long lx[1000],ly[1000]; bool vx[1000],vy[1000]; int n,m,k,s,N,ss,X,Y; int tail[20000],next[200000],sora[200000]; long long cost[200000],slack[1000]; int f[500][500]; bool find(int x) { long long tmp; if (vx[x]) return false; vx[x]=true; for (int i=x,ne;next[i];) { i=next[i],ne=sora[i]; tmp=lx[x]+ly[ne]-cost[i]; if ((!vy[ne]) && (tmp==0)) { vy[ne]=true; if (b1[ne]==0 || find(b1[ne])) { b1[ne]=x; return true; } } else slack[ne]=min(tmp,slack[ne]); } return false; } void link(int x,int y,long long z) { ++ss,next[tail[x]]=ss,tail[x]=ss,sora[ss]=y,cost[ss]=z,next[ss]=0; lx[x]=max(lx[x],z); c[x][y]=z; } long long dist(point p,point q) { return abs(p.x-q.x)+abs(p.y-q.y); } void origin() { for (int i=1;i<=m;i++) for (int j=1;j<=n;j++) if (!f[i][j]) p[1][++Y]=point(i,j); N=Y+Y,ss=N; for (int i=1;i<=N;i++) tail[i]=i,next[i]=0; for (int i=1;i<=N;i++) lx[i]=-oo,ly[i]=0; for (int i=1;i<=N;i++) for (int j=1;j<=N;j++) c[i][j]=oo; for (int i=1;i<=X;i++) for (int j=1;j<=Y;j++) { long long dd=dist(p[0][i],p[1][j]); dd=dd*-1000000+p[1][j].x*-10000+p[1][j].y*-100; // dd=-dd; link(i,j+Y,dd); } for (int i=X+1;i<=Y;i++) for (int j=1;j<=Y;j++) link(i,j+Y,-oo); } void km() { for (int i=1;i<=N;i++) b1[i]=0; for (int i=1;i<=Y;i++) { for (int j=1;j<=N;j++) vx[j]=false; for (int j=1;j<=N;j++) vy[j]=false; for (int j=1;j<=N;j++) slack[j]=oo; for (;!find(i);) { long long d=oo; for (int j=Y+1;j<=Y+Y;j++) if (!vy[j]) d=min(d,slack[j]); for (int j=Y+1;j<=Y+Y;j++) if (vy[j]) ly[j]+=d; else slack[j]-=d; for (int j=1;j<=Y;j++) if (vx[j]) lx[j]-=d; for (int j=1;j<=N;j++) vx[j]=false; for (int j=1;j<=N;j++) vy[j]=false; } } } bool cmp(int i,int j) { return c[i][b1[i]]>c[j][b1[j]]; } int main() { scanf("%d%d%d%d",&m,&n,&k,&s); memset(f,0,sizeof(f)); X=0,Y=0; for (int i=1;i<=k;i++) { int x,y; scanf("%d%d",&x,&y); f[x][y]=1; p[0][++X]=point(x,y); } for (int i=1;i<=s;i++) { int x,y; scanf("%d%d",&x,&y); f[x][y]=2; } origin(); km(); for (int i=Y+1;i<=Y+Y;i++) b1[b1[i]]=i; for (int i=1;i<=X;i++) vx[i]=0; for (int i=1;i<=Y;i++) vy[i]=0; for (int t=1;t<=k;t++) { for (int i=1;i<=X;i++) if (!vx[i]) { long long mind=oo; int mini=0; for (int j=1;j<=Y;j++) if (!vy[j]) { long long d=dist(p[0][i],p[1][j]); if (d<mind) { mind=d; mini=j; } else if (d==mind) { if (p[1][mini].x>p[1][j].x) { mini=j; } else if (p[1][mini].x==p[1][j].x) { if (p[1][mini].y>p[1][j].y) mini=j; } } } // cout<<i<<' '<<mini<<' '<<mind<<' '<<b1[i]-n<<endl; if (mini+Y==b1[i]) { vx[i]=1; u[t]=i; vy[mini]=1; break; } } } printf("%d",u[1]); for (int i=2;i<=k;i++) printf(" %d",u[i]); printf("\n"); return 0; }
#include <cstdio> #include <cstdlib> #include <cstring> #include <iostream> #include <algorithm> const int oo=1073741819; using namespace std; char s[205][1005]; int f[205][205]; int b[205],slack[205],vx[205],vy[205],lx[205],ly[205]; int n; bool km(int x) { int ne,tmp; if (vx[x]) return 0; vx[x]=1; for (int i=1;i<=n;i++) { ne=i; tmp=lx[x]+ly[ne]-f[x][ne]; if (!vy[ne] && (!tmp)) { vy[ne]=1; if (!b[ne] || km(b[ne])) { b[ne]=x; return 1; } } else if (tmp<slack[ne]) slack[ne]=tmp; } return 0; } void origin() { for (int i=1;i<=n;i++) for (int j=1;j<=n;j++) f[i][j]=0; } int check(char a[],char b[]) { int len1=strlen(a+1),len2=strlen(b+1); int len=min(len1,len2); for (int i=1;i<=len;i++) if (a[len1-i+1]!=b[i]) return i-1; return len; } int main() { for (;scanf("%d",&n)==1;) { origin(); for (int i=1;i<=n;i++) scanf("%s",s[i]+1); for (int i=1;i<=n;i++) for (int j=1;j<=n;j++) if (i!=j) f[i][j]=check(s[i],s[j]); else f[i][j]=0; // f[i][j]=check(s[i],s[j]); for (int i=1;i<=n;i++) lx[i]=0,ly[i]=0; for (int i=1;i<=n;i++) for (int j=1;j<=n;j++) lx[i]=max(lx[i],f[i][j]); memset(b,0,sizeof(b)); int ans=0; for (int i=1;i<=n;i++) { memset(vx,0,sizeof(vx)); memset(vy,0,sizeof(vy)); memset(slack,127,sizeof(slack)); for (;!km(i);) { int d=oo; for (int j=1;j<=n;j++) if (!vy[j]) d=min(d,slack[j]); for (int j=1;j<=n;j++) if (vy[j]) ly[j]+=d;else slack[j]-=d; for (int j=1;j<=n;j++) if (vx[j]) lx[j]-=d; memset(vx,0,sizeof(vx)),memset(vy,0,sizeof(vy)); } } for (int i=1;i<=n;i++) ans+=f[b[i]][i]; printf("%d\n",ans); } return 0; }