问题描述:
就是 有N*N的方阵 有一个人 要从(1,1) 走到(n,n) 只能向右或者向下 每个位置都有金钱。。。 当然 他走过之后 就 为0 了、、。 问他要走K次。。 最多能拿多少钱。。
解析:
果断的最大费用网络流啊。。。 将一个点 分成两个点 之间 连一条 容量为1 的 费用为 金钱数的费用
再连一条 容量为k-1费用为0的 边。。。 之后要是 两个位置能想走 就连一条边。。。
#include <iostream> using namespace std; const int MAXN = 5000 + 10; const int MAXE = 20000 + 50; int map[MAXN][MAXN]; // map[i][j] = t:点i和点j之间的边权为t int adj[MAXN]; // adj[u] = k:从点u出发的第一条边的编号为k int pre[MAXN]; // pre[v] = k:在增广路上,到达点v的边的编号为k int dis[MAXN]; // dis[u] = d:从起点s到点u的路径长为d int que[MAXN]; // 模拟队列 bool inq[MAXN]; // inq[u]:点u是否在队列中 int e; // 拆点建图后总的边数 int ans; // 最终答案:从(1,1)到(n,n)走k次后所能得到的最大值 struct EDGE { int u; int v; int cap; int cost; int next; }; EDGE edges[MAXE]; // 图 // 加入新边u-->v:容量为cap,费用为cost void _AddEdge(int u, int v, int cap, int cost) { edges[e].u = u; edges[e].v = v; edges[e].cap = cap; edges[e].cost = cost; edges[e].next = adj[u]; adj[u] = e; e++; } void AddEdge(int u, int v, int cap, int cost) { _AddEdge(u, v, cap, cost); _AddEdge(v, u, 0, -cost); } // 在源点s和汇点t之间找一条增广路 bool Spfa(int s, int t) { int u, v; int head, tail; // 初始化 head = 0; tail = 1; memset(inq, false, sizeof(inq)); memset(pre, -1, sizeof(pre)); memset(dis, -1, sizeof(dis)); que[head] = s; inq[s] = true; dis[s] = 0; while (tail != head) { u = que[head]; inq[u] = false; // 遍历从点u出发的边: 编号为k的边,u--->v for (int k=adj[u]; k!=-1; k=edges[k].next) { v = edges[k].v; // 最大费用流 if (edges[k].cap>0 && dis[v]<dis[u]+edges[k].cost) { dis[v] = dis[u] + edges[k].cost; pre[v] = k; if (!inq[v]) { inq[v] = true; que[tail++] = v; if (tail == MAXN) { tail = 0; } } } } head++; if (head == MAXN) { head = 0; } } return dis[t] > 0; } void Edmonds_Karp(int s, int t) { for (int k=pre[t]; k!=-1; k=pre[edges[k].u]) { // 更新正向流量 edges[k].cap -= 1; // 更新反向流量 edges[k^1].cap += 1; // 异或^:偶数加1,奇数减1 ans += edges[k].cost; } } void Input(int &n, int &k) { scanf("%d%d", &n, &k); for (int i=1; i<=n; ++i) { for (int j=1; j<=n; ++j) { scanf("%d", &map[i][j]); } } } // 拆点建图 void CreateGraph(int n, int k) { // 拆点:化点为边 for (int i=1; i<=n; ++i) { for (int j=1; j<=n; ++j) { int u = (i-1) * n + j; int v = u + n * n; AddEdge(u, v, 1, map[i][j]); AddEdge(u, v, k, 0); // 向下走 if (i < n) { AddEdge(v, u+n, k, 0); } // 向右走 if (j < n) { AddEdge(v, u+1, k, 0); } } } int _n = 2 * n * n + 1; AddEdge(0, 1, k, 0); AddEdge(2*n*n, _n, k, 0); } int main() { int n, k; e = 0; ans = 0; memset(adj, -1, sizeof(adj)); Input(n, k); CreateGraph(n,k); int _n = 2 * n * n + 1; while (Spfa(0, _n)) { Edmonds_Karp(0, _n); } printf("%d\n", ans); return 0; }