poj 2195 Going Home (最小费用 最大流)

最小费用最大流解决矩阵人进屋问题
本文介绍了一种使用最小费用最大流算法解决矩阵中人进入不同房子问题的方法,通过构建图模型,计算最少行走步数,提供了解决此类问题的高效算法策略。
  1 /*
  2 将 maxn 定位 200  不是超时 就是wa 定位300 32ms 过  纠结。。。。。。。 
  3 
  4 题意:一个row*col的矩阵,m表示人,H表示房子,.表示空地,人数和房子数相等,如下图:
  5         5 5
  6         HH..m
  7         .....
  8         .....
  9         .....
 10         mm..H
 11 现在要让所有的人都进入不同的房子内,问总共最少走多少步?
 12 将 人看作是 源点 房子 看作是 汇点
 13  
 14 思路:最小费用最大流。
 15 
 16 */
 17 
 18 #include<stdio.h>
 19 #include<string.h>
 20 #define maxn 300
 21 #define inf 0x7fffffff
 22 #include<cmath>
 23 int min(int x,int y)
 24 {
 25     if(x<y)return x;
 26     else return y;
 27 }
 28 struct node
 29 {
 30     int x;
 31     int y;
 32 }h[maxn],man[maxn];
 33 int map[maxn][maxn],vis[maxn],cap[maxn][maxn],dis[maxn];
 34 int que[maxn],pre[maxn];
 35 int num,ans;
 36 int SPFA()
 37 {
 38 
 39     int i;
 40     memset(vis,0,sizeof(vis));
 41      for(i=0;i<=num;i++)dis[i]=inf;
 42      dis[0]=0;
 43      vis[0]=1;
 44 
 45      int head=0,tail=0;
 46      que[0]=0;
 47      tail++;
 48      while(head!=tail)
 49      {
 50          int k=que[head];
 51 
 52          vis[k]=0;
 53          for(i=0;i<=num;i++)
 54          {
 55              if(cap[k][i]&&dis[i]>dis[k]+map[k][i])
 56              {
 57                  dis[i]=dis[k]+map[k][i];
 58                  pre[i]=k;
 59 
 60                  if(!vis[i])
 61                  {
 62                      vis[i]=1;
 63                      que[tail++]=i;
 64                      if(tail==maxn)tail=0;
 65                  }
 66              }
 67          }
 68          head++;
 69          if(head==maxn)head=0;
 70 
 71      }
 72      if(dis[num]<inf)return 1;//这里要注意 和最大流的不同
 73      else
 74      return 0;
 75 }
 76 void end()
 77 {
 78     int i,sum=inf;
 79     for(i=num;i!=0;i=pre[i])
 80     {
 81         sum=min(sum,cap[pre[i]][i]);
 82     }
 83     for(i=num;i!=0;i=pre[i])
 84     {
 85         cap[pre[i]][i]-=sum;
 86         cap[i][pre[i]]+=sum;
 87         ans+=map[pre[i]][i]*sum;
 88     }
 89 
 90 }
 91 int main()
 92 {
 93     int hnum,mnum,n,m,i,j;
 94     char c;
 95     while(scanf("%d%d",&n,&m)!=EOF)
 96     {
 97         if(n==0&&m==0)break;
 98         hnum=0;
 99         mnum=0;
100         getchar();
101         for(i=0;i<n;i++)
102         {
103             for(j=0;j<m;j++)
104             {
105                 scanf("%c",&c);
106                 if(c=='H')
107                 {
108                     h[++hnum].x=i;
109                     h[hnum].y=j;
110                 }
111                 if(c=='m')
112                 {
113                     man[++mnum].x=i;
114                     man[mnum].y=j;
115                 }
116             }
117             getchar();
118         }
119         memset(cap,0,sizeof(cap));
120         memset(map,0,sizeof(map));
121         for(i=1;i<=mnum;i++)
122         {
123 
124             for(j=1;j<=hnum;j++)
125             {
126 
127                 cap[i][j+mnum]=1;
128                 map[i][j+mnum]=fabs(man[i].x-h[j].x)+fabs(man[i].y-h[j].y);
129                 map[j+mnum][i]=-map[i][j+mnum];
130             }
131         }
132         num=mnum+hnum+1;
133         for(i=1;i<=mnum;i++)
134         {
135             map[0][i]=map[i][0]=0;
136             cap[0][i]=1;
137 
138         }
139         for(i=mnum+1;i<num;i++)
140         {
141             map[i][num]=map[num][i]=0;
142             cap[i][num]=1;
143         }
144         ans=0;
145         while(SPFA())end();
146         printf("%d\n",ans);
147 
148 
149     }
150 }

转载于:https://www.cnblogs.com/acSzz/archive/2012/05/05/2484603.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值