zoukankan      html  css  js  c++  java
  • 【HDU 1533】 Going Home (KM)

    Going Home

    Problem Description
    On a grid map there are n little men and n houses. In each unit time, every little man can move one unit step, either horizontally, or vertically, to an adjacent point. For each little man, you need to pay a $1 travel fee for every step he moves, until he enters a house. The task is complicated with the restriction that each house can accommodate only one little man. 

    Your task is to compute the minimum amount of money you need to pay in order to send these n little men into those n different houses. The input is a map of the scenario, a '.' means an empty space, an 'H' represents a house on that point, and am 'm' indicates there is a little man on that point. 

    You can think of each point on the grid map as a quite large square, so it can hold n little men at the same time; also, it is okay if a little man steps on a grid with a house without entering that house.
    Input
    There are one or more test cases in the input. Each case starts with a line giving two integers N and M, where N is the number of rows of the map, and M is the number of columns. The rest of the input will be N lines describing the map. You may assume both N and M are between 2 and 100, inclusive. There will be the same number of 'H's and 'm's on the map; and there will be at most 100 houses. Input will terminate with 0 0 for N and M.
    Output
    For each test case, output one line with the single integer, which is the minimum amount, in dollars, you need to pay. 
    Sample Input
    2 2 .m H. 5 5 HH..m ..... ..... ..... mm..H 7 8 ...H.... ...H.... ...H.... mmmHmmmm ...H.... ...H.... ...H.... 0 0
    Sample Output
    2 10 28
    Source
     
    【题意】
      

    给你一个类似这样的图

    ...H....

    ...H....

    ...H....

    mmmHmmmm

    ...H....
    ...H....
    ...H....

    问所有H移动到所有m上花费最少的步数
     
    【分析】
     
      这题题解都是费用流,可能不卡费用流。
      我打的是n^3 KM,不过求的是最小边权的最佳匹配,所以把边权先取反然后再做。
      记得一开始初始化lx的时候是-INF 不是0,有负边。
     
    代码如下:
      1 #include<cstdio>
      2 #include<cstdlib>
      3 #include<cstring>
      4 #include<iostream>
      5 #include<algorithm>
      6 #include<queue>
      7 using namespace std;
      8 #define Maxn 110
      9 #define Maxm 10010
     10 #define INF 0xfffffff
     11 
     12 struct node
     13 {
     14     int x,y,c,next;
     15 }t[Maxm];int len;
     16 int first[Maxn];
     17 
     18 int mymin(int x,int y) {return x<y?x:y;}
     19 int mymax(int x,int y) {return x>y?x:y;}
     20 int myabs(int x) {return x>0?x:-x;}
     21 
     22 int hx[Maxn],hy[Maxn],mx[Maxn],my[Maxn];
     23 int fn;
     24 
     25 void ins(int x,int y,int c)
     26 {
     27     t[++len].x=x;t[len].y=y;t[len].c=-c;
     28     t[len].next=first[x];first[x]=len;
     29 }
     30 
     31 int lx[Maxn],ly[Maxn];
     32 bool visx[Maxn],visy[Maxn];
     33 int slack[Maxn],match[Maxn];
     34 
     35 char s[Maxn];
     36 
     37 bool ffind(int x)
     38 {
     39     visx[x]=1;
     40     for(int i=first[x];i;i=t[i].next) if(!visy[t[i].y])
     41     {
     42         int y=t[i].y;
     43         if(lx[x]+ly[y]==t[i].c)
     44         {
     45             visy[y]=1;
     46             if(!match[y]||ffind(match[y]))
     47             {
     48                 match[y]=x;
     49                 return 1;
     50             }
     51         }
     52         else slack[y]=mymin(slack[y],lx[x]+ly[y]-t[i].c);
     53     }
     54     return 0;
     55 }
     56 
     57 void solve()
     58 {
     59     memset(match,0,sizeof(match));
     60     memset(ly,0,sizeof(ly));
     61     // memset(lx,0,sizeof(lx));
     62     for(int i=1;i<=fn;i++)
     63     {
     64         lx[i]=-INF;
     65         for(int j=first[i];j;j=t[j].next) lx[i]=mymax(lx[i],t[j].c);
     66     }
     67     
     68     for(int i=1;i<=fn;i++)
     69     {
     70         for(int j=1;j<=fn;j++)
     71             slack[j]=INF;
     72         while(1)
     73         {
     74             memset(visx,0,sizeof(visx));
     75             memset(visy,0,sizeof(visy));
     76             if(ffind(i)) break;
     77             
     78             int delta=INF;
     79             for(int j=1;j<=fn;j++) if(!visy[j]) 
     80               delta=mymin(delta,slack[j]);
     81             
     82             if(delta==INF) return ;
     83             
     84             for(int j=1;j<=fn;j++)
     85             {
     86                 if(visx[j]) lx[j]-=delta;
     87                 if(visy[j]) ly[j]+=delta;
     88                 else slack[j]-=delta;
     89             }
     90         }
     91     }
     92 }
     93 
     94 int main()
     95 {
     96     int n,m;
     97     while(1)
     98     {
     99         scanf("%d%d",&n,&m);
    100         if(n==0&&m==0) break;
    101         hx[0]=mx[0]=0;
    102         for(int i=1;i<=n;i++)
    103         {
    104             scanf("%s",s);
    105             for(int j=0;j<m;j++)
    106             {
    107                 if(s[j]=='H') hx[++hx[0]]=i,hy[hx[0]]=j+1;
    108                 else if(s[j]=='m') mx[++mx[0]]=i,my[mx[0]]=j+1;
    109             }
    110         }
    111         len=0;
    112         memset(first,0,sizeof(first));
    113         for(int i=1;i<=hx[0];i++)
    114          for(int j=1;j<=mx[0];j++)
    115             ins(i,j,myabs(hx[i]-mx[j])+myabs(hy[i]-my[j]));
    116         fn=hx[0];
    117         solve();
    118         int ans=0;
    119         for(int i=1;i<=fn;i++) ans+=lx[i]+ly[i];
    120         printf("%d
    ",-ans);
    121     }
    122     return 0;
    123 }
    HDU 1533

    容易打错的地方是visx 和 visy 的标记。

    表示的是是否为增广路上的点,前提当然是他也在相等子图上。

    2016-10-27 09:45:40

     
  • 相关阅读:
    关于测试开发及其他——写在离职之前
    牛腩新闻发布系统——初探CSS
    牛腩新闻发布系统——后台前台整合技术
    Android Audio Focus的应用(requestAudioFocus)
    正则表达式详解
    牛腩新闻发布系统——初探JQuery,AJAX
    牛腩新闻发布系统——初探Javascript
    进入中文维基百科的方法
    *args 和**kwargs 的溯源
    mathematica9激活
  • 原文地址:https://www.cnblogs.com/Konjakmoyu/p/6002776.html
Copyright © 2011-2022 走看看