Kaka's Matrix Travels

POJ

洛咕

给出一个\(n*n\)的矩阵,每一格有一个非负整数\(A_{i,j},(A_{i,j} <= 1000)\),现在从\((1,1)\)出发,可以往右或者往下走,最后到达\((n,n)\),每达到一格,把该格子的数取出来,该格子的数就变成\(0\),这样一共走\(K\)次,现在要求\(K\)次所达到的方格的数的和最大.\((1<=n<=50, 0<=k<=10).\)

分析:构建费用流模型(点边转化,拆点法).每个格子\((i,j\))对应一个节点\((i-1)*n+j\),拆成一个入点和一个出点,入点向出点连两条有向边,一条容量为1,费用为格子\((i,j)\)中的数(表示第一次经过该点是把数取走);另一条容量\(k-1\),费用为\(0\)(表示之后再经过该点时,不能再取数了).\((i,j)\)的出点还要向\((i,j+1)\)\((i+1,j)\)的入点连有向边,容量为\(k\),费用为\(0\)(怎么走都不会有取数).

然后以\((1,1)\)为源点,\((n,n)\)为汇点,求最大费用最大流即可.

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<queue>
#include<map>
#include<set>
#define ll long long
using namespace std;
inline int read(){
    int x=0,o=1;char ch=getchar();
    while(ch!='-'&&(ch<'0'||ch>'9'))ch=getchar();
    if(ch=='-')o=-1,ch=getchar();
    while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
    return x*o;
}
const int N=200005;//懒得想数组具体要开多大了
int n,k,s,t,max_flow,ans;
int dis[N],visit[N],pre[N],incf[N];
int tot,head[N],nxt[N],to[N],limit[N],w[N];
inline void add(int a,int b,int c,int d){
	nxt[++tot]=head[a];head[a]=tot;
	to[tot]=b;limit[tot]=c;w[tot]=d;
	nxt[++tot]=head[b];head[b]=tot;
	to[tot]=a;limit[tot]=0;w[tot]=-d;
}
inline bool spfa(){
	for(int i=1;i<N;++i)dis[i]=-1e9,visit[i]=0;
	queue<int>q;q.push(s);dis[s]=0;visit[s]=1;
	incf[s]=1<<30;
	while(q.size()){
		int u=q.front();q.pop();visit[u]=0;
		for(int i=head[u];i;i=nxt[i]){
			if(!limit[i])continue;
			int v=to[i];
			if(dis[v]<dis[u]+w[i]){
				dis[v]=dis[u]+w[i];
				incf[v]=min(incf[u],limit[i]);
				pre[v]=i;
				if(!visit[v])visit[v]=1,q.push(v);
			}
		}
	}
	if(dis[t]==-1e9)return false;
	return true;
}
inline void update(){
	int x=t;
	while(x!=s){
		int i=pre[x];
		limit[i]-=incf[t];
		limit[i^1]+=incf[t];
		x=to[i^1];
	}
	max_flow+=incf[t];
	ans+=dis[t]*incf[t];
}
int main(){
	n=read(),k=read();s=1;t=2*n*n;tot=1;
	for(int i=1;i<=n;++i){
		for(int j=1;j<=n;++j){
			int val=read();
			add((i-1)*n+j,(i-1)*n+j+n*n,1,val);
			add((i-1)*n+j,(i-1)*n+j+n*n,k-1,0);
			if(j+1<=n)add((i-1)*n+j+n*n,(i-1)*n+j+1,k,0);
			if(i+1<=n)add((i-1)*n+j+n*n,i*n+j,k,0);
		}
	}
	while(spfa())update();
	printf("%d\n",ans);
    return 0;
}

posted on 2019-09-30 21:12  PPXppx  阅读(137)  评论(0编辑  收藏  举报