关闭

POJ-2195 最小费用最大流模板题

3597人阅读 评论(0) 收藏 举报

     曾经看网络流~搞了最大流~搞了最小割..搞到最小费用最大流就卡住了..因为那时候不会SPFA..刚才拿过来看...感觉理解如何来求了..试着自己写了一个去A..就过了这道模板题..

     POJ2195的构图很简单了...其实最好的解法应该是KM..去年暑假就试着用KM写过这题..结果WA得一直不明不白..今天用网络流1A了...

    关于最小费用最大流的课件还是很多的...我目前的理解就是每次找起点到终点的最短路径做为增广路经来更新..直道找不到最短路径...而找最短路径就需要边的权值..初始时每条边的权值为该边单位流量费用..而在找到一条路径做剩余网络时..这条路径每条边做反向边,权值为正向单位流量费用的相反数...

     至于为什么要用SPFA而不能用Djikstra..是因为在做剩余网络时会出现负边...做SPFA..只有当边还有剩余的容量时才能更新...


Program: 

#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);
            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;
                      s[i][j+NumMan].w=absI(man[i].x-house[j].x)+absI(man[i].y-house[j].y); 
               }
            for (i=1;i<=NumMan;i++)
            {
                    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;
}


0
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:685592次
    • 积分:12251
    • 等级:
    • 排名:第1162名
    • 原创:620篇
    • 转载:3篇
    • 译文:0篇
    • 评论:178条
    最新评论