HDU-1533 Going Home

Going Home

题意:给你一张图,图上有若干个人和若干个屋子,现在要使的这若干个人都进到屋子里,并且一个屋子只能进一个人,求总步数最小。

题解:最小费用流。将图转化成边的关系,然后求解。

代码:

  1 #include<bits/stdc++.h>
  2 using namespace std;
  3 #define Fopen freopen("_in.txt","r",stdin); freopen("_out.txt","w",stdout);
  4 #define LL long long
  5 #define ULL unsigned LL
  6 #define fi first
  7 #define se second
  8 #define pb push_back
  9 #define lson l,m,rt<<1
 10 #define rson m+1,r,rt<<1|1
 11 #define max3(a,b,c) max(a,max(b,c))
 12 #define min3(a,b,c) min(a,min(b,c))
 13 
 14 typedef pair<int,int> pll;
 15 const int INF = 0x3f3f3f3f;
 16 const LL mod =  (int)1e9+7;
 17 const int N = 50005;
 18 char str[205][205];
 19 int px[N], py[N];
 20 int head[N], to[N], ct[N], w[N], nt[N];
 21 int d[N], vis[N];
 22 int pre[N], id[N];
 23 int n, m, s, t, tot;
 24 
 25 void add(int u, int v, int val, int cost){
 26     to[tot] = v;
 27     ct[tot] = cost;
 28     w[tot] = val;
 29     nt[tot] = head[u];
 30     head[u] = tot++;
 31 }
 32 
 33 void get_G(){
 34     int p = 0, z = 0;
 35     s = 0;
 36     for(int i = 1; i <= n; i++)
 37         for(int j = 1; j <= m; j++)
 38             if(str[i][j] == 'H'){
 39                 ++p;
 40                 px[p] = i;
 41                 py[p] = j;
 42             }
 43     for(int i = 1; i <= n; i++)
 44         for(int j = 1; j <= m; j++)
 45             if(str[i][j] == 'm'){
 46                 z++;
 47                 add(s,z+p,1,0);
 48                 add(z+p,s,0,0);
 49                 for(int k = 1; k <= p; k++){
 50                     add(z+p,k,1,abs(i-px[k])+abs(j-py[k]));
 51                     add(k,z+p,0,-(abs(i-px[k])+abs(j-py[k])));
 52                 }
 53             }
 54     t = p + z + 1;
 55     for(int i = 1; i <= p; i++){
 56         add(i,t,1,0);
 57         add(t,i,0,0);
 58     }
 59 }
 60 void init(){
 61     memset(head,-1,sizeof(head));
 62     tot = 0;
 63 }
 64 
 65 int spfa(){
 66     queue<int> q;
 67     memset(d, INF, sizeof(d));
 68     memset(vis, 0, sizeof(vis));
 69     memset(pre, -1, sizeof(vis));
 70     d[s] = 0;
 71     q.push(s);
 72     while(!q.empty()){
 73         int u = q.front(); q.pop();
 74         vis[u] = 0;
 75         for(int i = head[u]; ~i; i = nt[i]){
 76             if(w[i] > 0 && d[to[i]] > d[u] + ct[i]){
 77                 d[to[i]] = d[u] + ct[i];
 78                 pre[to[i]] = u;
 79                 id[to[i]] = i;
 80                 if(!vis[to[i]]){
 81                     vis[to[i]] = 1;
 82                     q.push(to[i]);
 83                 }
 84             }
 85         }
 86 
 87     }
 88     return d[t] < INF;
 89 }
 90 
 91 int MaxFlow(){
 92     int Mi = INF;
 93     int sum = 0;
 94     while(spfa()){
 95         Mi = INF;
 96         for(int i = t; i != s; i = pre[i])
 97             Mi = min(Mi, w[id[i]]);
 98         for(int i = t; i != s; i = pre[i]){
 99             w[id[i]] -= Mi;
100             w[id[i]^1] += Mi;
101         }
102         sum += d[t];
103     }
104     return sum;
105 }
106 
107 int main(){
108     while(~scanf("%d%d", &n, &m), n+m){
109         init();
110         for(int i = 1; i <= n; i++)
111             scanf("%s", str[i]+1);
112         get_G();
113         printf("%d\n", MaxFlow());
114     }
115     return 0;
116 }
KM 费用流

第一次写KM费用流,跑的特别慢,希望下次能改进。

转载于:https://www.cnblogs.com/MingSD/p/9303369.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值