給出一個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。容量網絡構建完成後,求最小費用最大流即可。