题意:给你一张图,图上有若干个人和若干个屋子,现在要使的这若干个人都进到屋子里,并且一个屋子只能进一个人,求总步数最小。
题解:最小费用流。将图转化成边的关系,然后求解。
代码:
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 ", MaxFlow()); 114 } 115 return 0; 116 }
第一次写KM费用流,跑的特别慢,希望下次能改进。