POJ3422 Kaka's Matrix Travels
阿新 • • 發佈:2018-11-24
嘟嘟嘟
費用流經典題。
大體的建圖大家應該都會,就是每一個點向他的下面和右面點連邊。但是沒有解決把點權轉化為邊權的問題。
但是這麼建圖的話不能確定這個點的權應該給那一條邊,因此有一個很經典同時也非常使實用的方法:拆點!這樣的話點權就是\(v -> v'\)的邊權了。
對於題中的要求,簡單來說就是隻有第一次經過這條邊能加分,因此\(v -> v'\)之間連兩條邊,分別是一條容量為\(1\),費用為\(a_{i, j}\)的邊和一條容量為\(INF\),費用為\(0\)的邊。
然後其餘的邊都是容量為\(INF\),費用為\(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 = 5e3 + 5; const int maxe = 2e4 + 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, k, s, t, a[55][55], sum = 0; struct Edge { int nxt, from, to, cap, c; }e[maxe]; int head[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; } bool in[maxn]; int dis[maxn], pre[maxn], flow[maxn]; bool spfa() { Mem(dis, -1); Mem(in, 0); 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] != -1; } int maxCost = 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; } maxCost += flow[t] * dis[t]; } void MCMF() { while(spfa()) update(); } int num(int x, int y) { return (x - 1) * n + y; } int main() { Mem(head, -1); n = read(); k = read(); s = 0; t = ((n * n) << 1) + 1; for(int i = 1; i <= n; ++i) for(int j = 1; j <= n; ++j) a[i][j] = read(); addEdge(s, 1, k, 0); addEdge(t - 1, t, k, 0); for(int i = 1; i <= n; ++i) for(int j = 1; j <= n; ++j) { int u = num(i, j), v = num(i, j) + n * n; addEdge(u, v, 1, a[i][j]); addEdge(u, v, INF, 0); if(i + 1 <= n) addEdge(v, num(i + 1, j), INF, 0); if(j + 1 <= n) addEdge(v, num(i, j + 1), INF, 0); } MCMF(); write(maxCost), enter; return 0; }