首页 > 代码库 > Bipartitegraph2195

Bipartitegraph2195

题目大意:图中有nmannhome,并且一个人只能住在一个房子里面,房子和人的个数是相等的。并且每个人移动一步的代价是1,怎么使

所有人住在房子里,并且使所有人的代价和最小。

给出一个n×m的图,m表示人,H表示房子,.表示空地,当然房子不算障碍物,可以穿过

 

方法用最大流最小费 或者最佳二分匹配KM算法 

 

 

  

最大流最小费

#include<iostream>

#include<string.h>

#include<stdio.h>

#include<queue>

#define oo 2000000000

using namespace std;

struct node1

{

      int y,x;

}man[105],house[105];

struct node2

{

      int f,w;

}s[205][205];

struct node3

{

      int pre,w;

}dp[205];

int n,m,NumMan,NumHouse,ans;

char arc[105][105];

bool used[205],inqueue[205];

queue<int> myqueue;

bool SPFA()

{

      int h,k,i;

      while (!myqueue.empty()) myqueue.pop();

      memset(dp,-1,sizeof(dp));

      memset(inqueue,false,sizeof(inqueue));

      myqueue.push(0);  dp[0].w=0;      

      while (!myqueue.empty())

      {

             h=myqueue.front();

             myqueue.pop();

             inqueue[h]=false;

             for (i=0;i<=n;i++)

             if (s[h][i].f && (dp[i].pre==-1 || dp[i].w>dp[h].w+s[h][i].w))

             {

                     dp[i].w=dp[h].w+s[h][i].w;

                     dp[i].pre=h;

                     if (!inqueue[i])

                     {

                            inqueue[i]=true;

                            myqueue.push(i);

                     }

             }

      }

      if (dp[n].pre==-1) return false;

      return true;

}

void MinCostOfMaxFlow()

{

      int i,m,way[205],Flow;

      ans=0;

      while (SPFA())

      {

            m=0;

            i=n;

            memset(way,0,sizeof(way));

            while (1)

            {

                  way[++m]=i;

                  if (!i) break;

                  i=dp[i].pre;

            }

            Flow=oo;

            for (i=1;i<m;i++) 

               if (s[way[i+1]][way[i]].f<Flow) Flow=s[way[i+1]][way[i]].f;

            for (i=1;i<m;i++)

            {

                  ans+=s[way[i+1]][way[i]].w*Flow;

                  s[way[i+1]][way[i]].f-=Flow;

                  s[way[i]][way[i+1]].f+=Flow;

              //    s[way[i]][way[i+1]].w=-s[way[i+1]][way[i]].w;//这一句没必要,前面赋值过了 就不用了

            } 

      }

}

int absI(int x)

{

      if (x<0) return -x;

      return x;

}

int main()

{

     // freopen("input.txt","r",stdin);

      //freopen("output.txt","w",stdout);

      int i,j;

      while (~scanf("%d%d\n",&n,&m))

      {

            if (!n && !m) break;

            for (i=1;i<=n;i++) gets(arc[i]+1); //arc[i][1]开始,而不是arc[i][0]

            NumMan=NumHouse=0;

            for (i=1;i<=n;i++)

               for (j=1;j<=m;j++)

                  if (arc[i][j]==‘m‘)

                  {

                         NumMan++;

                         man[NumMan].y=i;

                         man[NumMan].x=j;                                     

                  }else

                  if (arc[i][j]==‘H‘)

                  {

                         NumHouse++;

                         house[NumHouse].y=i;

                         house[NumHouse].x=j;

                  } 

            memset(s,0,sizeof(s));

            for (i=1;i<=NumMan;i++)

               for (j=1;j<=NumHouse;j++)

               {

                      s[i][j+NumMan].f=1; //MAN节点和HOUSE节点分开,防止在一维数组里面出现重合。流量总值为1,因为一个人最多只能去一个房间

                      s[i][j+NumMan].w=absI(man[i].x-house[j].x)+absI(man[i].y-house[j].y); 

  s[j+NumMan][i].w=-s[i][j+NumMan].w;//这一句还是要加上。

               }

            for (i=1;i<=NumMan;i++)//超级源点到人的代价是1,总流量是人的总流量,为1

            {

                    s[0][i].f=1;

                    s[0][i].w=0; 

            }

            for (i=1;i<=NumHouse;i++)//每个房子最多住一个人

            {

                    s[i+NumHouse][NumMan+NumHouse+1].f=1;

                    s[i+NumHouse][NumMan+NumHouse+1].w=0;

            }

            n=NumMan+NumHouse+1;  

            MinCostOfMaxFlow();

            printf("%d\n",ans);            

      }

      return 0;

}

 

Bipartitegraph2195