POJ3422费用流
Posted df-yimeng
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了POJ3422费用流相关的知识,希望对你有一定的参考价值。
Description:
一个N * N的奖赏地图,你可以走k次这个地图,但是每一次你走过一个有分的节点,你获得得分,但这个节点的得分都要清零,问你走k次地图的最大得分
Solution:
把得分变成负数就变成最小费用问题了,看看题目的要求进行建图,首先每个节点的访问次数最多也就k次,然后有分的点访问一次后就没分了,可以变成1,k-1的访问,所以转换成经典的拆点建图问题
·源点到入口 —— 容量k —— 费用0
·出口到汇点 —— 容量k —— 费用0
·地图中的节点拆分成x1,x2
·x1 - x2 加两次边 一次:容量为1 —— 费用是 - cost 另一次是 容量是k - 1 —— 费用是0
·x2 到其它可达点 —— 容量k —— 费用 0
所以写这篇博客目的也就是学习一下,生活条件的建图思想,把分数只能走一次转化成建两类边的思想,是精彩点
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #include <cmath> #include <queue> #define inf (1 << 28) using namespace std; const int maxn = 50500; const int maxm = 100100; int n,m,k; struct node { int to,val,cost,pre; }e[maxm]; int id[maxn]; int cnt; void add(int from,int to,int val,int cost) { e[cnt].to = to; e[cnt].val = val; e[cnt].cost = cost; e[cnt].pre = id[from]; id[from] = cnt++; swap(from,to); e[cnt].to = to; e[cnt].val = 0; e[cnt].cost = -cost; e[cnt].pre = id[from]; id[from] = cnt++; } void init() { memset(id,-1,sizeof(id)); cnt = 0; } int dis[maxn]; int pre[maxn]; int path[maxn]; int vis[maxn]; bool spfa(int s,int t) { memset(pre,-1,sizeof(pre)); memset(vis,0,sizeof(vis)); for(int i = 0;i < maxn ;++i) dis[i] = inf; dis[s] = 0; vis[s] = 1; queue<int> q; q.push(s); while(q.size()) { int now = q.front(); q.pop(); for(int i = id[now];~i;i = e[i].pre) { int to = e[i].to; int val = e[i].val; int cost = e[i].cost; if(val > 0 && dis[now] + cost < dis[to]) { dis[to] = dis[now] + cost; pre[to] = now; path[to] = i; if(!vis[to]) { vis[to] = 1; q.push(to); } } } vis[now] = 0; } if(pre[t] == -1)return false; return true; } int mcmf(int s,int t) { int c = 0; while(spfa(s,t)) { int mf = inf; for(int now = t;now != s;now = pre[now]) { if(e[path[now]].val < mf) mf = e[path[now]].val; } for(int now = t;now != s;now = pre[now]) { e[path[now]].val -= mf; e[path[now]^1].val += mf; c += mf * e[path[now]].cost; } } return c; } int coss[55][55]; int main() { while(~scanf("%d%d",&n,&k)) { init(); int s = 0; int t = 2 * n * n + 1; for(int i = 1;i <= n;++i) { for(int j = 1;j <= n;++j) { scanf("%d",&coss[i][j]); } } add(s,1,k,0); add(2*n*n,t,k,0); for(int i = 1;i <= n;++i) { for(int j = 1;j <= n;++j) { int id1 = (i - 1) * n + j; int id2 = n * n + id1; add(id1,id2,1,-coss[i][j]); add(id1,id2,k-1,0); if(i == n && j == n)continue; if(i + 1 > n) add(id2,id1+1,k,0); else if(j + 1 > n) add(id2,id1+n,k,0); else { add(id2,id1+n,k,0); add(id2,id1+1,k,0); } } } printf("%d ",mcmf(s,t) * -1 ); } return 0; }
以上是关于POJ3422费用流的主要内容,如果未能解决你的问题,请参考以下文章