POJ2195 Going Home
阿新 • • 發佈:2018-11-24
嘟嘟嘟
費用流水題。
從源點向每一個人連一條容量為1,費用為0的邊;從每一個人向每一棟房子連一條容量為1,費用為兩點歐幾里得距離的邊;從每一棟房子向匯點連一條容量為1,費用為0的邊。
跑最小費用最大流即可。
祭寫\(spfa\)時又忘了彈棧後把標記陣列清空。
#include<cstdio> #include<iostream> #include<cmath> #include<algorithm> #include<cstring> #include<cstdlib> #include<cctype> #include<vector> #include<stack> #include<queue> using namespace std; #define enter puts("") #define space putchar(' ') #define Mem(a, x) memset(a, x, sizeof(a)) #define rg register typedef long long ll; typedef double db; const int INF = 0x3f3f3f3f; const db eps = 1e-8; const int maxn = 105; const int maxe = 5e6 + 5; inline ll read() { ll ans = 0; char ch = getchar(), last = ' '; while(!isdigit(ch)) last = ch, ch = getchar(); while(isdigit(ch)) ans = (ans << 1) + (ans << 3) + ch - '0', ch = getchar(); if(last == '-') ans = -ans; return ans; } inline void write(ll x) { if(x < 0) x = -x, putchar('-'); if(x >= 10) write(x / 10); putchar(x % 10 + '0'); } int n, m, s, t; char a[maxn][maxn]; struct Edge { int nxt, from, to, cap, c; }e[maxe]; int head[maxn * maxn], ecnt = -1; void addEdge(int x, int y, int w, int c) { e[++ecnt] = (Edge){head[x], x, y, w, c}; head[x] = ecnt; e[++ecnt] = (Edge){head[y], y, x, 0, -c}; head[y] = ecnt; } int num(int i, int j) { return (i - 1) * m + j; } struct Node { int x, y; }h[maxn * maxn]; int cnt = 0; void build(int x, int y) { addEdge(s, num(x, y), 1, 0); for(int i = 1; i <= cnt; ++i) addEdge(num(x, y), num(h[i].x, h[i].y), 1, abs(x - h[i].x) + abs(y - h[i].y)); } bool in[maxn * maxn]; int dis[maxn * maxn], pre[maxn * maxn], flow[maxn * maxn]; bool spfa() { Mem(in, 0); Mem(dis, 0x3f); queue<int> q; q.push(s); in[s] = 1; dis[s] = 0; flow[s] = INF; while(!q.empty()) { int now = q.front(); q.pop(); in[now] = 0; for(int i = head[now], v; i != -1; i = e[i].nxt) { v = e[i].to; if(e[i].cap && dis[now] + e[i].c < dis[v]) { dis[v] = dis[now] + e[i].c; pre[v] = i; flow[v] = min(flow[now], e[i].cap); if(!in[v]) in[v] = 1, q.push(v); } } } return dis[t] != INF; } int minCost = 0; void update() { int x = t; while(x != s) { int i = pre[x]; e[i].cap -= flow[t]; e[i ^ 1].cap += flow[t]; x = e[i].from; } minCost += flow[t] * dis[t]; } void MCMF() { while(spfa()) update(); } void init() { Mem(head, -1); ecnt = -1; minCost = 0; } int main() { while(scanf("%d%d", &n, &m) != EOF && n && m) { init(); s = 0; t = n * m + 1; for(int i = 1; i <= n; ++i) scanf("%s", a[i] + 1); for(int i = 1; i <= n; ++i) for(int j = 1; j <= m; ++j) if(a[i][j] == 'H') addEdge(num(i, j), t, 1, 0), h[++cnt] = (Node){i, j}; for(int i = 1; i <= n; ++i) for(int j = 1; j <= m; ++j) if(a[i][j] == 'm') build(i, j); MCMF(); write(minCost), enter; } return 0; }