Luogu1006 传纸条 与 Luogu P2045方格取数加强版 (费用流)
Posted gzygzy
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Luogu1006 传纸条 与 Luogu P2045方格取数加强版 (费用流)相关的知识,希望对你有一定的参考价值。
Luogu1006 传纸条 与 Luogu P2045方格取数加强版
其实就是这几道题
在一个有m*n 个方格的棋盘中
每个方格中有一个正整数
现要从在方格中从左上角到右下角取数,只能向右或向下走
每走到一个格子就可以把这个位置上的数取走(下次经过就没有了)
1.让你走1次,求取出的数的总和最大是多少
2.让你走2次,求取出的数的总和最大是多少
3.让你走k次,求取出的数的总和最大是多少
对于第一问,十分显然.
设(f[i][j])表示(i)行(j)列的最大价值,转移即可。
第二问,较上一题有些难度。
考虑有性质:
1,如果两人相遇,那么一定不是最优的
2.走n+m步数.
用性质1:设状态(f[i][j][k][l])表示第一个人走到i,j第二个人走到k,l两人不相交的最大价值.
转移的时候只要判断一下路径是否相交就ok了。
没有完全利用好性质
用性质2:设状态(f[k][i][j])表示第一个人和第二个人都走了k步,第一个人到了((i,k?j)),第二个人到了((j,k?j))的最大价值.
也就是传纸条
第三问
考虑费用流。
开一个源点连向((1,1)),流量为(k),费用为(0)。
对于一个点,先拆点。
一条是流量为(inf),费用为(0),另外一条是流量(inf),费用为(a)
然后向下和右连边.
/*header*/
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
#include <cmath>
#include <map>
#include <queue>
#define gc getchar()
#define pc putchar
#define ll long long
#define mk make_pair
#define fi first
#define se second
using std::min;
using std::max;
using std::swap;
const int inf = 0x3f3f3f3f;
inline int gi() {
int x = 0,f = 1;char c = gc;
while(c < '0' || c > '9') {if(c == '-')f = -1;c = gc;}
while(c >= '0' && c <= '9') {x = x * 10 + c - '0';c = gc;}return x * f;
}
const int maxN = 5000 + 7;
const int maxM = 100000 + 7 ;
using namespace std;
int n, m, s, t, ans, maxflow, k;
int head[maxN];
struct Node{
int u,v,flow,spend,nex;
}Map[maxM];
int dis[maxN],vis[maxN],num,path[maxN];
void init() {
s = n * n * 2 + 1;
t = s + 1;
num = -1;
memset(head,-1,sizeof(head));
return;
}
void add_Node(int u,int v,int w,int spend) {
Map[++ num] = (Node) {u , v, w, spend, head[u]};head[u] = num;
Map[++ num] = (Node) {v , u, 0, -spend, head[v]};head[v] = num;
return ;
}
bool spfa() {
queue<int>q;
q.push(s);
memset(dis,0x3f,sizeof(dis));
memset(path,0,sizeof(path));
dis[s] = 0;
vis[s] = true;
while(!q.empty()) {
int p = q.front();q.pop();
vis[p] = false;
for(int i = head[p];i != -1;i = Map[i].nex) {
int v = Map[i].v;
if(dis[v] > dis[p] + Map[i].spend && Map[i].flow) {
dis[v] = dis[p] + Map[i].spend;
path[v] = i;
if(!vis[v]) {
q.push(v);
vis[v] = true;
}
}
}
}
if(dis[t] == 0x3f3f3f3f) return false;
return true;
}
int min(int a,int b) {return a > b ? b : a ;}
void f() {
int mn = 0x7fffffff;
for(int i = t;i != s;i = Map[path[i]].u)
mn = min(mn,Map[path[i]].flow);
ans += mn;
for(int i = t;i != s;i = Map[path[i]].u) {
Map[path[i]].flow -= mn;
Map[path[i] ^ 1].flow += mn;
maxflow += mn * Map[path[i]].spend;
}
}
void EK() {
while(spfa())
f();
printf("%d",-maxflow);
return ;
}
int a[57][57];
int main() {
n = gi();int k = gi();
init();
for(int i = 1;i <= n;++ i) for(int j = 1;j <= n;++ j) a[i][j] = gi();
for(int i = 1;i <= n;++ i) for(int j = 1;j <= n;++ j) add_Node((i - 1) * n + j, (i - 1) * n + j + n * n, inf, 0) , add_Node((i - 1) * n + j, (i - 1) * n + j + n * n, 1, - a[i][j]);
add_Node(s , 1, k, 0);
for(int i = 1;i <= n;++ i) {
for(int j = 1;j <= n;++ j) {
if(i < n) add_Node((i - 1) * n + j + n * n , i * n + j, inf, 0);
if(j < n) add_Node((i - 1) * n + j + n * n , (i - 1) * n + j + 1, inf, 0);
}
}
add_Node(2 * n * n , t, k, 0);
EK();
return 0;
}
以上是关于Luogu1006 传纸条 与 Luogu P2045方格取数加强版 (费用流)的主要内容,如果未能解决你的问题,请参考以下文章