POJ 2195 Going Home KM/最小费用流

http://poj.org/problem?id=2195

题意:N个人 N个房子,问N个人进入N个房子一共最少走几步

KM算法,原理看了一天多,就是把 求最大权匹配的问题 转化成  求完备匹配的问题(x端点都被匹配,或者y端点都被匹配)

关于原理百度百科讲的不错  http://baike.baidu.com/view/739278.htm

总之,原理查了好多资料

还有一个地方,题目让求最小,KM用于求最大,所以做一些处理最后ans加个负号

代码:

#include<iostream>
#include<cstdio>
#include<string>
#include<cstring>
#include<algorithm>
#define Max(a,b)a>b?a:b
#define Min(a,b)a<b?a:b
#define inf 1000000
#define MAX 105
using namespace std;
int map[MAX][MAX],lx[MAX],ly[MAX],link[MAX];
bool vx[MAX],vy[MAX];
int n,m;
struct
{
    int r,c;
}M[MAX],H[MAX];

bool dfs(int u)
{
    int j;
    vx[u]=1;
    for(j=1;j<=m;j++)
       if(!vy[j]&&map[u][j]==lx[u]+ly[j])//!!!map[u][j]==lx[u]+ly[j]
       {
           vy[j]=1;
           if(!link[j]||dfs(link[j]))
              {
                  link[j]=u;
                  return true;
              }
       }
     return false;
}

int KM()
{
    int i,j,k;
    for(i=1;i<=n;i++)
    {   lx[i]=-inf;
       for(j=1;j<=m;j++)
         lx[i]=Max(lx[i],map[i][j]);//每个map[i][j]都已初始化
    }
    memset(ly,0,sizeof(ly));

    memset(link,0,sizeof(link));
    for(i=1;i<=n;i++)
    {
        while(1)
        {
            memset(vx,0,sizeof(vx));
            memset(vy,0,sizeof(vy));
            if(dfs(i))break;
            //修改 lx ly
            int MIN=inf;

            for(j=1;j<=n;j++)
              if(vx[j])
                for(k=1;k<=m;k++)
                 if(!vy[k])
                   MIN=Min(MIN,lx[j]+ly[k]-map[j][k]);

            for(j=1;j<=n;j++)if(vx[j])lx[j]-=MIN;//lx[j]--;错错错
            for(j=1;j<=m;j++)if(vy[j])ly[j]+=MIN;
        }
    }
    int ans=0;
    for(i=1;i<=m;i++)
       if(link[i]) ans+=map[link[i]][i];
    return ans;
}

int main()
{
    int r,c,i,j;
    char ch;
    while(cin>>r>>c)
    {
        if(r==0&&c==0)break;
        n=m=0;
        for(i=1;i<=r;i++)
           for(j=1;j<=c;j++)
           {
               cin>>ch;
               if(ch=='m')
               {
                 M[++n].r=i;
                 M[n].c=j;
               }
               else if(ch=='H')
               {
                   H[++m].r=i;
                   H[m].c=j;
               }
           }
           for(i=1;i<=n;i++)
              for(j=1;j<=m;j++)
                map[i][j]=-abs(M[i].r-H[j].r)-abs(M[i].c-H[j].c);
        cout<<-KM()<<endl;
    }
    return 0;
}

  

又一次写这个题,WA了n次后,发现题意弄错了,题目没说有‘H'的格子不能走啊,每个方格都可以走,囧。。。以后不能想当然了  如果每个方格都能走的话,就不需要dfs搜索找最短路了。。。下面的代码是用的dfs找最短路,就浪费时间了

代码:

 

#include<iostream>
#include<cstdio>
#include<string>
#include<cstring>
#define inf 1<<26
#define nMAX 200
using namespace std;
int n,r,c;
int link[nMAX],a[nMAX][nMAX],map[nMAX][nMAX],lx[nMAX],ly[nMAX];
bool vx[nMAX],vy[nMAX],vs[nMAX][nMAX];
int dir[4][2]={-1,0,0,1,1,0,0,-1};
struct node
{
    int x,y,step;
}qu[nMAX*nMAX];
int min(int a,int b)
{
    return a<b?a:b;
}
int max(int a,int b)
{
     return a>b?a:b;
}
void bfs(int x,int y,int u)
{
    int i,j,k,beg,tail;
    beg=0,tail=1;
    qu[0].x=x,qu[0].y=y,qu[0].step=0;
    memset(vs,0,sizeof(vs));
    vs[x][y]=1;
    while(beg!=tail)
    {
        node tt,t=qu[beg++];
        for(k=0;k<4;k++)
        {
            tt.x=t.x+dir[k][0],tt.y=t.y+dir[k][1];
            if(tt.x<1||tt.x>r||tt.y<1||tt.y>c||vs[tt.x][tt.y])continue;
            tt.step=t.step+1;
            qu[tail++]=tt;
            vs[tt.x][tt.y]=1;
            if(a[tt.x][tt.y]>0)map[u][a[tt.x][tt.y]]=-tt.step;
        }
    }
}

bool DFS(int u)
{
    int j;
    vx[u]=1;
    for(j=1;j<=n;j++)
    {
        if(!vy[j]&&map[u][j]==lx[u]+ly[j])
        {
            vy[j]=1;
            if(link[j]==-1||DFS(link[j]))
            {
               link[j]=u;
               return 1;
            }
        }
    }
    return 0;
}
int KM()
{
    int i,j,k,MIN;
    memset(link,-1,sizeof(link));
    for(i=1;i<=n;i++)
    {
        lx[i]=-inf,ly[i]=0;
        for(j=1;j<=n;j++)
            lx[i]=max(lx[i],map[i][j]);
    }
    memset(link,-1,sizeof(link));
    for(i=1;i<=n;i++)
    {
        while(1)
        {
            memset(vx,0,sizeof(vx));
            memset(vy,0,sizeof(vy));
            if(DFS(i))break;
            MIN=inf;
            for(j=1;j<=n;j++)
                if(vx[j])
                    for(k=1;k<=n;k++)
                        if(!vy[k])
                            MIN=min(MIN,lx[j]+ly[k]-map[j][k]);
            for(j=1;j<=n;j++)if(vx[j])lx[j]-=MIN;
            for(j=1;j<=n;j++)if(vy[j])ly[j]+=MIN;
        }
    }
    int sum=0;
    for(i=1;i<=n;i++)
    {// cout<<"map["<<link[i]<<"][="<<i<<"]="<<map[link[i]][i]<<endl;
        if(link[i])sum+=map[link[i]][i];
    }
    return sum;
}
int main()
{
    int i,j;
    int sm,sh;
    char ch;
    while(~scanf("%d%d",&r,&c))
    {
        if(r==0&&c==0)break;
        sm=0;
        for(i=1;i<=r;i++)
        {
            getchar();
            for(j=1;j<=c;j++)
            {
                scanf("%c",&ch);
                if(ch=='H')a[i][j]=-1;
                else if(ch=='m')a[i][j]=++sm;
                else a[i][j]=0;
            }
        }
        sh=0;
        memset(map,0,sizeof(map));
        for(i=1;i<=r;i++)
            for(j=1;j<=c;j++)
            {
                if(a[i][j]==-1)bfs(i,j,++sh);
            }
        n=sh;
        int ans=-KM();
        printf("%d\n",ans);
    }
    return 0;
}

 

  

 

posted @ 2012-02-14 03:00  快乐.  阅读(226)  评论(0编辑  收藏  举报