【codevs 1227】方格取数2(费用流)
1227 方格取数 2
时间限制: 1 s 空间限制: 128000 KB题目等级 : 大师Master
题目描述 Description
给出一个n*n的矩阵,每一格有一个非负整数Aij,(Aij <= 1000)现在从(1,1)出发,可以往右或者往下走,最后到达(n,n),每达到一格,把该格子的数取出来,该格子的数就变成0,这样一共走K次,现在要求K次所达到的方格的数的和最大
输入描述 Input Description
第一行两个数n,k(1<=n<=50, 0<=k<=10)
接下来n行,每行n个数,分别表示矩阵的每个格子的数
输出描述 Output Description
一个数,为最大和
样例输入 Sample Input
3 1
1 2 3
0 2 1
1 4 2
样例输出 Sample Output
11
数据范围及提示 Data Size & Hint
1<=n<=50, 0<=k<=10
【题解】【网络流费用流】
【建图:拆点,将一个点拆成两个,两点之间连两条边,一条边流量为1,权值为方格里的数(表示每个数只能取一次);另一条边流量为走的次数k,权值为0(即每个方格可以走多次,但数只能取一次)。 然后再加上源点和汇点,源点到(1,1)的边的流量为k,权值为0;(n,n)到汇点的边的流量为k,权值为0】
【要考虑dis数组的初值应赋为极小值,再逐渐向大更新】
#include<queue>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int a[50100],next[50100],p[5010],remain[50100],w[50100],tot=-1;
int dis[50100],last[50100];
int n,k,maxflow,mincost,n1,tt;
bool b[50100];
inline void add(int x,int y,int z,int cost)
{
tot++; a[tot]=y; next[tot]=p[x]; p[x]=tot; remain[tot]=z; w[tot]=cost;
tot++; a[tot]=x; next[tot]=p[y]; p[y]=tot; remain[tot]=0; w[tot]=-cost;
return;
}
inline int addflow(int s,int t)
{
int sum=0x7fffffff,now=t;
while (now!=s)
{
sum=min(sum,remain[last[now]]);
now=a[last[now]^1];
}
now=t;
while (now!=s)
{
remain[last[now]]-=sum;
remain[last[now]^1]+=sum;
now=a[last[now]^1];
}
return sum;
}
inline bool spfa(int s,int t)
{
int x;
memset(dis,128,sizeof(dis));
memset(b,true,sizeof(b));
queue<int>que; x=dis[0];
b[s]=false; dis[s]=0; que.push(s);
while (!que.empty())
{
int u,v;
u=que.front(); que.pop();
v=p[u]; b[u]=true;
while (v!=-1)
{
if (remain[v]&&dis[a[v]]<dis[u]+w[v])
{
dis[a[v]]=dis[u]+w[v];
last[a[v]]=v;
if (b[a[v]])
{
b[a[v]]=false;
que.push(a[v]);
}
}
v=next[v];
}
}
if (dis[t]<0) return false;
int ans=addflow(s,t);
maxflow+=ans;
mincost+=dis[t]*ans;
return true;
}
int main()
{
int i,j;
memset(p,-1,sizeof(p));
memset(next,-1,sizeof(next));
tot=-1; tt=0;
scanf("%d%d",&n,&k);
n1=n*n;
for (i=1;i<=n;++i)
for (j=1;j<=n;++j)
{
int x;
scanf("%d",&x);
tt++;
add(tt,tt+n1,1,x);
add(tt,tt+n1,k,0);
if (i!=n) add(tt+n1,tt+n,k,0);
if (j!=n) add(tt+n1,tt+1,k,0);
}
n1*=2; n1++;
add(0,1,k,0);
add(n1-1,n1,k,0);
while(spfa(0,n1));
printf("%d",mincost);
return 0;
}
既然无能更改,又何必枉自寻烦忧