km算法+slack优化 poj3565

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;
}


你可能感兴趣的:(c,优化,算法,百度,input)