【費用流】【網絡流24題】【P4013】 數字梯形問題
阿新 • • 發佈:2019-03-20
img null des 給定 圖片 允許 mit load flow 的路徑。
個點而不是 \(m\) 個
Description
給定一個由 \(n\) 行數字組成的數字梯形如下圖所示。
梯形的第一行有 \(m\) 個數字。從梯形的頂部的 \(m\) 個數字開始,在每個數字處可以沿左下或右下方向移動,形成一條從梯形的頂至底的路徑。
分別遵守以下規則:
- 從梯形的頂至底的 \(m\) 條路徑互不相交;
- 從梯形的頂至底的 \(m\) 條路徑僅在數字結點處相交;
- 從梯形的頂至底的 \(m\) 條路徑允許在數字結點相交或邊相交。
Limitation
\(1~\leq~n,~m~\leq~20\)
Solution
解釋一下題意,邊不相交指的是不能有兩條路徑同時經過 \(u \rightarrow~v\)
先考慮限制 \(3\),也就是沒有限制的情況,做法非常顯然,上一層向下一層的數字連邊,容量為無窮代表這條邊可以走無窮次,花費為 \(0\)。每個數字都拆一下點,兩個點之間連邊容量為無窮,代表可以選這個點無數次,花費為這個點的權值代表經過他付出的代價,\(s\) 向第一層連容量為 \(1\) 費用為 \(0\) 的邊,最後一層向 \(t\) 連容量為無窮費用為 \(0\) 的邊,跑最大費用最大流即可。
考慮限制 \(2\),一條邊只能經過一次,於是將邊的容量置為 \(1\) 即可。
考慮限制 \(1\),同理將點的容量置成 \(1\) 即可。
然後如果你Wa前兩個點需要註意梯形的最下面會有 \(n + m\)
Code
#include <cstdio> #include <cstring> #include <queue> #include <algorithm> #ifdef ONLINE_JUDGE #define freopen(a, b, c) #endif typedef long long int ll; namespace IPT { const int L = 1000000; char buf[L], *front=buf, *end=buf; char GetChar() { if (front == end) { end = buf + fread(front = buf, 1, L, stdin); if (front == end) return -1; } return *(front++); } } template <typename T> inline void qr(T &x) { char ch = IPT::GetChar(), lst = ' '; while ((ch > '9') || (ch < '0')) lst = ch, ch=IPT::GetChar(); while ((ch >= '0') && (ch <= '9')) x = (x << 1) + (x << 3) + (ch ^ 48), ch = IPT::GetChar(); if (lst == '-') x = -x; } namespace OPT { char buf[120]; } template <typename T> inline void qw(T x, const char aft, const bool pt) { if (x < 0) {x = -x, putchar('-');} int top=0; do {OPT::buf[++top] = static_cast<char>(x % 10 + '0');} while (x /= 10); while (top) putchar(OPT::buf[top--]); if (pt) putchar(aft); } const int maxn = 5010; const int INF = 0x3f3f3f3f; struct Edge { int u, v, flow, fee; Edge *nxt, *bk; Edge(const int _u, const int _v, const int _flow, const int _fee, Edge* &h) : u(_u), v(_v), flow(_flow), fee(_fee), nxt(h) { h = this; } ~Edge() { if (this->nxt) delete this->nxt; } }; Edge *hd[maxn], *pre[maxn]; inline void cont(const int _u, const int _v, const int _flow, const int _fee) { auto u = new Edge(_u, _v, _flow, _fee, hd[_u]), v = new Edge(_v, _u, 0, -_fee, hd[_v]); (u->bk = v)->bk = u; } int n, m, s, t, ans; int MU[maxn][maxn], id[maxn][maxn][2], dist[maxn], canag[maxn]; bool inq[maxn]; std::queue<int>Q; void EK(); bool spfa(); void argu(); void setedge(int x); void setpoint(int x); int main() { freopen("1.in", "r", stdin); qr(m); qr(n); for (int i = 1; i <= n; ++i) { for (int j = 1, k = m + i; j < k; ++j) { id[i][j][0] = ++t; id[i][j][1] = ++t; qr(MU[i][j]); } } s = ++t; ++t; setpoint(1); setedge(1); EK(); setpoint(INF); setedge(1); EK(); setpoint(INF); setedge(INF); EK(); return 0; } void setpoint(int x) { for (int i = 1; i <= t; ++i) { delete hd[i]; hd[i] = NULL; } for (int i = 1; i <= m; ++i) { cont(s, id[1][i][0], 1, 0); } for (int i = 1; i <= n; ++i) { for (int j = 1, k = i + m - 1; j <= k; ++j) { cont(id[i][j][0], id[i][j][1], x, MU[i][j]); } } } void setedge(int x) { for (int i = 1; i < n; ++i) { int di = i + 1; for (int j = 1, k = i + m - 1; j <= k; ++j) { cont(id[i][j][1], id[di][j][0], x, 0); cont(id[i][j][1], id[di][j + 1][0], x, 0); } } for (int j = 1, k = m + n - 1; j <= k; ++j) cont(id[n][j][1], t, INF, 0); } void EK() { ans = 0; while (spfa()) argu(); qw(ans, '\n', true); } bool spfa() { memset(canag, 0, sizeof canag); for (int i = 1; i <= t; ++i) dist[i] = -INF; dist[s] = 0; Q.push(s); canag[s] = INF; while (!Q.empty()) { int u = Q.front(); Q.pop(); inq[u] = false; for (auto e = hd[u]; e; e = e->nxt) if (e->flow > 0) { int v = e->v; if (dist[v] < (dist[u] + e->fee)) { dist[v] = dist[u] + e->fee; if (!inq[v]) Q.push(v); inq[v] = true; canag[v] = std::min(canag[u], e->flow); pre[v] = e; } } } return dist[t] != -INF; } void argu() { ans += canag[t] * dist[t]; for (auto e = pre[t]; e; e = pre[e->u]) { e->flow -= canag[t]; e->bk->flow += canag[t]; } }
【費用流】【網絡流24題】【P4013】 數字梯形問題