大致题意:
给出N和K,表示一个N*N个区域组成的的方阵map,方阵的每个区域都有自己的一个值map[i][j]。现从(0,0)点走到(n,n)点走K次,规定只能向右走或者向下走,每经过一个区域取走区域中的值,map[i][j]变为0,一个区域可以被多次经过。求最多能取走多少值。
大致思路:
最小费用最大流。说实话一直觉得这道题算法叫最大费用最大流更合适,因为这里求的是取走费用总和的最大值。但是终归还是要用费用流的模版,毕竟只是最小费用流模版改了几个小地方而已。
建图方案。因为这里并不规定一个区域最多走多少次,但是能获得其上面数字map[i][j]的次数只有一次,所以这里可以将一个点拆作两个点再用两条边连接他们。一条的流量是1费用是map[i][j],代表能得到收入map[i][j]的次数只有一次。另一条流量是inf费用是0,代表这个点可以被0收入地经过无数次。再将其拆出的第二个点与其下方和右方的点连上一条边,流量为inf费用为0。设一个超级原点0连接1,这条边流量是K,费用是0。然后对构造出的图从0到第2*N*N个点使用最小费用最大流模版。
说到模版,本来想带poj 2135的模版来用,没想到tle了,最后看大牛的博客说在用spfa时使用堆栈会超时,换队列的spfa模版过了。哪位大牛知道这是为何的话麻烦帮忙给我解释解释啊。
给出N和K,表示一个N*N个区域组成的的方阵map,方阵的每个区域都有自己的一个值map[i][j]。现从(0,0)点走到(n,n)点走K次,规定只能向右走或者向下走,每经过一个区域取走区域中的值,map[i][j]变为0,一个区域可以被多次经过。求最多能取走多少值。
大致思路:
最小费用最大流。说实话一直觉得这道题算法叫最大费用最大流更合适,因为这里求的是取走费用总和的最大值。但是终归还是要用费用流的模版,毕竟只是最小费用流模版改了几个小地方而已。
建图方案。因为这里并不规定一个区域最多走多少次,但是能获得其上面数字map[i][j]的次数只有一次,所以这里可以将一个点拆作两个点再用两条边连接他们。一条的流量是1费用是map[i][j],代表能得到收入map[i][j]的次数只有一次。另一条流量是inf费用是0,代表这个点可以被0收入地经过无数次。再将其拆出的第二个点与其下方和右方的点连上一条边,流量为inf费用为0。设一个超级原点0连接1,这条边流量是K,费用是0。然后对构造出的图从0到第2*N*N个点使用最小费用最大流模版。
说到模版,本来想带poj 2135的模版来用,没想到tle了,最后看大牛的博客说在用spfa时使用堆栈会超时,换队列的spfa模版过了。哪位大牛知道这是为何的话麻烦帮忙给我解释解释啊。
详细代码:
#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std;
const int inf=99999999;
const int nMax=5005;
struct{
int v, cap, cost, next, re;
}edge[40005];
int n,m,ans;
int k,edgeHead[nMax];
int que[5005],pre[5005],dis[5005];
bool vis[5005];
void addEdge(int u,int v,int ca,int co){
edge[k].v=v;
edge[k].cap=ca;
edge[k].cost=co;
edge[k].next=edgeHead[u];
edge[k].re=k + 1;
edgeHead[u]=k ++;
edge[k].v=u;
edge[k].cap=0;
edge[k].cost=-co;
edge[k].next=edgeHead[v];
edge[k].re=k - 1;
edgeHead[v]=k ++;
}
bool spfa(){
int i, head = 0, tail = 1; // 长注释的地方就是从最小费用改到最大费用时需要变动的地方
for(i = 0; i <= n; i ++){
dis[i] = -1;
vis[i] = false;
}
dis[0] = 0;
que[0] = 0;
vis[0] = true;
while(head != tail){
int u = que[head];
for(i = edgeHead[u]; i != 0; i = edge[i].next){
int v = edge[i].v;
if(edge[i].cap && dis[v] <dis[u] + edge[i].cost){
dis[v] = dis[u] + edge[i].cost;
pre[v] = i;
if(!vis[v]){
vis[v] = true;
que[tail ++] = v;
if(tail == 5005) tail = 0;
}
}
}
vis[u] = false;
head++;
if(head ==5005) head = 0;
}
if(dis[n] ==-1) return false;///
return true;
}
void end(){
int u, p;
for(u = n; u != 0; u = edge[edge[p].re].v){
p = pre[u];
edge[p].cap -= 1;
edge[edge[p].re].cap += 1;
ans += edge[p].cost;
}
}
int main(){
int map[60][60];
int a,b,c,d,i,j,N,K;
k=1;
memset(edgeHead,0,sizeof(edgeHead));
memset(vis,0,sizeof(vis));
scanf("%d%d",&N,&K);
for(i=1;i<=N;i++){
for(j=1;j<=N;j++){
scanf("%d",&map[i][j]);
}
}
addEdge(0,1,K,0);
for(i=1;i<=N;i++){
for(j=1;j<=N;j++){
a=(i-1)*N+j;
a=a*2-1;
b=a+1;
addEdge(a,b,1,map[i][j]);
addEdge(a,b,K,0);
if(i<N)addEdge(b,a+2*N,K,0);
if(j<N)addEdge(b,b+1,K,0);
}
}
n=2*N*N;
ans=0;
while(spfa())end();
cout<<ans<<endl;
return 0;
}