POJ 3422 Kaka's Matrix Travels 最大费用最大流
2015-06-21 15:55
465 查看
题意:给你一个n×n的方格 每个格子有一个数 一个人从左上走到右下 每经过一个格子 就会将得到这个格子的点数 然后这个格子值变为零 问你这个人走k次 得到的最大值是多少
思路:刚做这个题的时候 想到既然一个格子的值只能取一次 那么是不是限定一个格子只能取一次呢 于是拆点后连一条容量为1的边 但发现这样就相当于限制了每个点的经过次数 而题目中并没有限制每个点经过的次数 想了半天也解决不了这个问题 看了题解又一次意识到自己脑洞是多么的小。。。正确的建图方法是 为了限制每个点的值只能取一次 首先要拆点 然后连边很巧妙 先连一条容量为一 费用为格子点数的相反数(最大费用最大流都费用是取反) 然后再连一条容量为INF 费用为0的边 代表如果多次经过这个点 费用就为零了
思路:刚做这个题的时候 想到既然一个格子的值只能取一次 那么是不是限定一个格子只能取一次呢 于是拆点后连一条容量为1的边 但发现这样就相当于限制了每个点的经过次数 而题目中并没有限制每个点经过的次数 想了半天也解决不了这个问题 看了题解又一次意识到自己脑洞是多么的小。。。正确的建图方法是 为了限制每个点的值只能取一次 首先要拆点 然后连边很巧妙 先连一条容量为一 费用为格子点数的相反数(最大费用最大流都费用是取反) 然后再连一条容量为INF 费用为0的边 代表如果多次经过这个点 费用就为零了
#include <cstdio> #include <cstring> #include <algorithm> using namespace std; #define REP( i, a, b ) for( int i = a; i < b; i++ ) #define FOR( i, a, b ) for( int i = a; i <= b; i++ ) #define CLR( a, x ) memset( a, x, sizeof a ) #define CPY( a, x ) memcpy( a, x, sizeof a ) const int maxn = 5000 + 10; const int maxe = 40000 + 10; const int INF = 0x3f3f3f3f; struct Edge{ int v, c, f, w; int next; Edge() {} Edge(int v, int c, int f, int w, int next) : v(v), c(c), f(f), w(w), next(next) {} }; struct MCMF{ int n, s, t; int d[maxn], cur[maxn], f[maxn]; int Head[maxn], cntE; int Q[maxn], head, tail, inq[maxn]; int flow; long long cost; Edge edge[maxe]; void Init(int n){ this -> n = n; cntE = 0; CLR(Head, -1); } void Add(int u, int v, int c, int w){ edge[cntE] = Edge(v, c, 0, w, Head[u]); Head[u] = cntE++; edge[cntE] = Edge(u, 0, 0, -w, Head[v]); Head[v] = cntE++; } int Spfa(){ head = tail = 0; CLR(d, INF); CLR(inq, 0); Q[tail++] = s; f[s] = INF; cur[s] = -1; d[s] = 0; while(head != tail){ int u = Q[head++]; if(head == maxn) head = 0; inq[u] = 0; for(int i = Head[u]; ~i; i = edge[i].next){ int v = edge[i].v; if(edge[i].c > edge[i].f && d[v] > d[u] + edge[i].w){ f[v] = min(f[u], edge[i].c - edge[i].f); d[v] = d[u] + edge[i].w; cur[v] = i; if(!inq[v]){ if(d[v] < d[Q[head]]){ if(head == 0) head = maxn; Q[--head] = v; } else{ Q[tail++] = v; if(tail == maxn) tail = 0; } inq[v] = 1; } } } } if(d[t] == INF) return 0; flow += f[t]; cost += (long long)f[t] * (long long)d[t]; for(int i = cur[t]; ~i; i = cur[edge[i^1].v]){ edge[i].f += f[t]; edge[i^1].f -= f[t]; } return 1; } long long Mcmf(int s, int t){ this -> s = s; this -> t = t; flow = 0; cost = 0; while(Spfa()); return cost; } }solver; int n, k; int num[51][51]; int Getid(int x, int y){ return n * (x - 1) + y; } void solve(){ int S = 0, T = 2 * n * n + 1; solver.Init(T + 1); FOR(i, 1, n) FOR(j, 1, n) scanf("%d", &num[i][j]); solver.Add(S, 1, k, 0); FOR(i, 1, n) FOR(j, 1, n){ int id = Getid(i, j); solver.Add(id, id + n * n, 1, -num[i][j]); solver.Add(id, id + n * n, INF, 0); if(j != n) solver.Add(id + n * n, Getid(i, j + 1), INF, 0); if(i != n) solver.Add(id + n * n, Getid(i + 1, j), INF, 0); } solver.Add(Getid(n, n) + n * n, T, k, 0); printf("%lld\n", -solver.Mcmf(S, T)); } int main() { //freopen("in.txt", "r", stdin); while(~scanf("%d%d", &n, &k)) solve(); return 0; }
相关文章推荐
- android gradle build process
- swift operator+()
- ubuntu下nginx安装手记
- Python实现删除文件但保留指定文件
- C缺陷与陷阱读书笔记
- OJ复数类--重载运算符+
- Android事件传递机制【按键事件】
- LaTeX Software & Manuals
- 附录一 4. 添加入站规则
- 猴子吃桃的递归问题
- Python os.system 和 os.popen的区别
- 详解——android系统软键盘的手动显示和隐藏
- POJ 3083 Bfs+Dfs
- 【Android UI设计与开发】第11期:顶部标题栏(二)ActionBar实现Tab选项卡和下拉导航列表
- poj 3836 P2P File Sharing System
- Gson简单实例
- 第十五周 阅读项目 二进制文件读取
- Struts2(六)手工编码方式进行输入校验
- Android开发通过adapter显示listview
- How do you explain Artifical Neural Network to a college student ?