给出一个n*n的矩阵,每一格有一个非负整数Aij,(Aij <= 1000)现在从(1,1)出发,可以往右或者往下走,最后到达(n,n),每达到一格,把该格子的数取出来,该格子的数就变成0,这样一共走K次,现在要求K次所达到的方格的数的和最大
第一行两个数n,k(1<=n<=50, 0<=k<=10)
接下来n行,每行n个数,分别表示矩阵的每个格子的数
一个数,为最大和
3 1
1 2 3
0 2 1
1 4 2
11
1<=n<=50, 0<=k<=10
题解:
本题是POJ 3422 卡卡的矩阵之旅 的弱化版,同时也是《图论算法理论、实现及应用》中的例题。原题有多组数据。
本题可以转化为最小费用最大流问题。
构建容量网络的方法如下:将每个位置拆成两个——出点和入点,出点和入点之间连接一条容量为1、费用为矩阵中该位置上的数值;若点p与q能连通,则连接p与q,n*n+p与n*n+q,p与n*n+q,n*n+p与q四条边,容量为无穷大,费用为 0;假设源点与汇点,源点与1、汇点与 2*n*n 之间连接边,容量为K,用为0。容量网络构建完成后,求最小费用最大流即可。
code:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
using namespace std;
#define INF 0x3f3f3f3f
#define MIN(a,b) ((a)<(b)?(a):(b))
int mat[55][55];
int n,k;
int head[5005];
int adj[25000];
int next[25000];
int point[25000];
int cost[25000];
int cap[25000];
int pre[5005];
int dis[5005];
bool fl[5005];
int max_flow;
int min_cost;
int edge_cnt;
void add(int u,int v,int cst,int cp)
{
next[edge_cnt]=head[u];
head[u]=edge_cnt;
point[edge_cnt]=v;
adj[edge_cnt]=u;
cost[edge_cnt]=cst;
cap[edge_cnt]=cp;
}
void cost_flow(int src,int tar)
{
while(1)
{
memset(pre,-1,sizeof(pre));
memset(dis,0x3f,sizeof(dis));
memset(fl,0,sizeof(fl));
queue<int>q;
q.push(src);
dis[src]=0;
while(!q.empty())
{
int u=q.front();
q.pop();
fl[u]=0;
for(int e=head[u];e!=-1;e=next[e])
{
if(cap[e]>0&&dis[u]+cost[e]<dis[point[e]])
{
dis[point[e]]=dis[u]+cost[e];
pre[point[e]]=e;
if(!fl[point[e]])
{
fl[point[e]]=1;
q.push(point[e]);
}
}
}
}
if(pre[tar]==-1)break;
int min=INF;
for(int i=tar;pre[i]!=-1;i=adj[pre[i]])
{
min=MIN(min,cap[pre[i]]);
}
for(int i=tar;pre[i]!=-1;i=adj[pre[i]])
{
cap[pre[i]]-=min;
//反边,反悔的机会
if(pre[i]&1)cap[pre[i]+1]+=min;
else cap[pre[i]-1]+=min;
}
max_flow+=min;
min_cost+=min*dis[tar];
}
}
int main()
{
while(~scanf("%d%d",&n,&k))
{
max_flow=0;
min_cost=0;
memset(head,-1,sizeof(head));
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
scanf("%d",&mat[i][j]);
}
}
edge_cnt=0;
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
int p3=(i-1)*n+j;
int p4=(i-1)*n+j+n*n;
edge_cnt++;
add(p3,p4,-mat[i][j],1);//负数,所以求的是最小费用,答案添负号就行了
edge_cnt++;
add(p4,p3,mat[i][j],1);
edge_cnt++;
add(p3,p4,0,k);
edge_cnt++;
add(p4,p3,0,0);
if(i<n)
{
int p1=(i-1)*n+j;
int p2=i*n+j;
//edge_cnt++;
//add(p1,p2,0,INF);
//edge_cnt++;
//add(p1,p2+n*n,0,INF);
edge_cnt++;
add(p1+n*n,p2,0,k);
edge_cnt++;
add(p2,p1+n*n,0,0);
//edge_cnt++;
//add(p1+n*n,p2+n*n,0,INF);
}
if(j<n)
{
int p1=(i-1)*n+j;
int p2=(i-1)*n+j+1;
//edge_cnt++;
//add(p1,p2,0,INF);
//edge_cnt++;
//add(p1,p2+n*n,0,INF);
edge_cnt++;
add(p1+n*n,p2,0,k);
edge_cnt++;
add(p2,p1+n*n,0,0);
//edge_cnt++;
//add(p1+n*n,p2+n*n,0,INF);
}
}
}
edge_cnt++;
add(0,1,0,k);
edge_cnt++;
add(1,0,0,0);
edge_cnt++;
add(n*n*2,n*n*2+1,0,k);
edge_cnt++;
add(n*n*2+1,n*n*2,0,0);
cost_flow(0,2*n*n+1);
printf("%d\n",-min_cost);
}
return 0;
}
本题是POJ 3422 卡卡的矩阵之旅 的弱化版,同时也是《图论算法理论、实现及应用》中的例题。原题有多组数据。
本题可以转化为最小费用最大流问题。
构建容量网络的方法如下:将每个位置拆成两个——出点和入点,出点和入点之间连接一条容量为1、费用为矩阵中该位置上的数值;若点p与q能连通,则连接p与q,n*n+p与n*n+q,p与n*n+q,n*n+p与q四条边,容量为无穷大,费用为 0;假设源点与汇点,源点与1、汇点与 2*n*n 之间连接边,容量为K,用为0。容量网络构建完成后,求最小费用最大流即可。