题目描述 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,权值为该点的权值
一条容量为INF,权值为0. 其余的地方自己YY就可以了
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<queue>
using namespace std;
int n,k,maxn;
int next[20000],point[10000],cost[20000],remain[20000],v[20000],tot=-1;
int dis[10000],laste[10000],can[10000];
const int inf=1e9;
void add(int x,int y,int z,int q)
{
tot++; next[tot]=point[x]; point[x]=tot; v[tot]=y; remain[tot]=z; cost[tot]=q;
tot++; next[tot]=point[y]; point[y]=tot; v[tot]=x; remain[tot]=0; cost[tot]=-q;
}
int addflow(int s,int t)
{
int minn=inf; int now=t;
while(now!=s)
{
minn=min(minn,remain[laste[now]]);
now=v[laste[now]^1];
}
now=t;
while(now!=s)
{
remain[laste[now]]-=minn;
remain[laste[now]^1]+=minn;
now=v[laste[now]^1];
}
return minn;
}
bool spfa(int s,int t)
{
for (int i=s;i<=t;i++)
dis[i]=-inf;
memset(can,0,sizeof(can));
dis[s]=0; can[s]=1;
queue<int> p; p.push(s);
while(!p.empty())
{
int now=p.front(); p.pop();
for (int i=point[now];i!=-1;i=next[i])
if (dis[v[i]]<dis[now]+cost[i]&&remain[i])
{
dis[v[i]]=dis[now]+cost[i];
laste[v[i]]=i;
if (!can[v[i]])
{
can[v[i]]=1;
p.push(v[i]);
}
}
can[now]=0;
}
if (dis[t]<0) return false;
maxn+=addflow(s,t)*dis[t];
return true;
}
void maxflow(int s,int t)
{
while (spfa(s,t));
}
int main()
{
freopen("a.in","r",stdin);
memset(next,-1,sizeof(next));
memset(point,-1,sizeof(point));
scanf("%d%d",&n,&k);
int num=n*n;
int sum=0;
add(0,1,k,0);
for (int i=1;i<=n;i++)
for (int j=1;j<=n;j++)
{
sum++;
int x; scanf("%d",&x);
add(sum,sum+num,inf,0),add(sum,sum+num,1,x);
if (j!=n)
add(sum+num,sum+1,inf,0);
if (i!=n)
add(sum+num,sum+n,inf,0);
}
add(num*2,num*2+1,k,0);
maxn=0;
maxflow(0,num*2+1);
printf("%d\n",maxn);
}