zoukankan      html  css  js  c++  java
  • POJ 3422 Kaka's Matrix Travels (K取方格数:最大费用流)

    题意

    给出一个n*n大小的矩阵,要求从左上角走到右下角,每次只能向下走或者向右走并取数,某位置取过数之后就只为数值0,现在求解从左上角到右下角走K次的最大值.

    思路

    经典的费用流模型:K取方格数。 构图方法:将矩阵的每个元素m[i][j]拆成两个点u=(i-1)*n+j和v=n*n+(i-1)*n+j,从u到v连两条边: 1> 连边(u,v),容量为1,费用值为m[i][j],这样可以保证每一个位置的数只被取一次 2> 连边(u,v),容量为INF,费用值为0,这样可以保证某位置取数被置为0之后,随便怎么取对最后的费用值不会产生影响 由于每次只能向下走或者向右走,所以需要连两条边: 1> 向下走:即从(i,j)到(i+1,j),连边v=n*n+(i-1)*n+j到i*n+j,容量为INF,费用为0 2> 向右走:即从(i,j)到(i,j+1),连边v=n*n+(i-1)*n+j到(i-1)*n+j+1,容量为INF,费用为0. 然后为了限制只走K次,需要添加源点s=0和汇点t=2*n*n+1,连边:s……矩阵左上角顶点1,容量为k,费用为0,连边矩阵右下角顶点被拆之后对应的顶点2*n*n……t,容量为K,费用为0,然后对所建立的图求解最大费用流即可.

    代码

    [cpp] #include <iostream> #include <cstdio> #include <cmath> #include <vector> #include <algorithm> #include <string> #include <queue> #include <cstring> #define MID(x,y) ((x+y)/2) #define MEM(a,b) memset(a,b,sizeof(a)) #define REP(i, begin, m) for (int i = begin; i < begin+m; i ++) using namespace std; const int MAXV = 200005; const int MAXE = 100005; const int oo = 0x3fffffff; template <class NodesType> struct Nodes{ NodesType dist; int pre, head; //pre存前趋边, head存前向星 bool visit; }; template <class EdgesType> struct Edges{ int u, v, next; EdgesType cost, flow; }; template <class T> struct MinCostMaxFlow{ Nodes <T> node[MAXV]; Edges <T> arc[2*MAXE]; int vn, en; void init(int n){ vn = n; en = 0; for (int i = 0; i <= n; i ++){ node[i].head = -1; } } void insert_flow(int u, int v, T flow, T cost){ arc[en].u = u; arc[en].v = v; arc[en].flow = flow; arc[en].cost = cost; arc[en].next = node[u].head; node[u].head = en ++; arc[en].v = u; arc[en].u = v; arc[en].flow = 0; arc[en].cost = -cost; arc[en].next = node[v].head; node[v].head = en ++; } void print_edges(){ for (int i = 0; i < en; i ++){ printf("u = %d v = %d flow = %d cost = %d ", arc[i].u, arc[i].v, arc[i].flow, arc[i].cost); } } queue <int> q; bool spfa(int s, int t){ for (int i = 1; i <= vn; i ++){ node[i].dist = oo; node[i].pre = -1; node[i].visit = false; } node[s].dist = 0; node[s].visit = true; q.push(s); while(!q.empty()){ int u = q.front(); q.pop(); node[u].visit = false; for (int i = node[u].head; i != -1; i = arc[i].next){ int v = arc[i].v; if (arc[i].flow > 0 && node[v].dist > node[u].dist + arc[i].cost){ node[v].dist = node[u].dist + arc[i].cost; node[v].pre = i; if (!node[v].visit){ node[v].visit = true; q.push(v); } } } } if (node[t].pre == -1) return 0; else return 1; } T solve(int s, int t, T &mincost){ mincost = 0; T maxflow = 0; while(spfa(s, t)){ T minflow = oo; for (int i = node[t].pre; i != -1; i = node[arc[i].u].pre){ minflow = min(minflow, arc[i].flow); } for (int i = node[t].pre; i != -1; i = node[arc[i].u].pre){ arc[i].flow -= minflow; arc[i^1].flow += minflow; mincost += arc[i].cost * minflow; } maxflow += minflow; } return maxflow; } }; MinCostMaxFlow <int> mcmf; int map[55][55]; int main(){ //freopen("test.in", "r", stdin); //freopen("test.out", "w", stdout); int n, k; while(scanf("%d %d", &n, &k) != EOF){ mcmf.init(2*n*n+2); mcmf.insert_flow(2*n*n+1, 1, k, 0); mcmf.insert_flow(2*n*n, 2*n*n+2, k, 0); REP(i, 1, n) REP(j, 1, n){ scanf("%d", &map[i][j]); int u = (i-1)*n+j; mcmf.insert_flow(u, u+n*n, 1, -map[i][j]); mcmf.insert_flow(u, u+n*n, oo, 0); if (i < n){ mcmf.insert_flow(u+n*n, u+n, oo, 0); } if (j < n){ mcmf.insert_flow(u+n*n, u+1, oo, 0); } } //mcmf.print_edges(); int res = 0; mcmf.solve(2*n*n+1, 2*n*n+2, res); printf("%d ", -res); } return 0; } [/cpp]
  • 相关阅读:
    PAT (Advanced Level) Practice 1100 Mars Numbers (20分)
    PAT (Advanced Level) Practice 1107 Social Clusters (30分) (并查集)
    PAT (Advanced Level) Practice 1105 Spiral Matrix (25分)
    PAT (Advanced Level) Practice 1104 Sum of Number Segments (20分)
    PAT (Advanced Level) Practice 1111 Online Map (30分) (两次迪杰斯特拉混合)
    PAT (Advanced Level) Practice 1110 Complete Binary Tree (25分) (完全二叉树的判断+分享致命婴幼儿错误)
    PAT (Advanced Level) Practice 1109 Group Photo (25分)
    PAT (Advanced Level) Practice 1108 Finding Average (20分)
    P6225 [eJOI2019]异或橙子 树状数组 异或 位运算
    P4124 [CQOI2016]手机号码 数位DP
  • 原文地址:https://www.cnblogs.com/AbandonZHANG/p/4114301.html
Copyright © 2011-2022 走看看