1227 方格取数 2

题目描述

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

输入输出格式

输入格式:

第一行两个数n,k(1<=n<=50, 0<=k<=10)

接下来n行,每行n个数,分别表示矩阵的每个格子的数

输出格式:

一个数,为最大和

输入输出样例

输入样例#1:
3 1
1 2 3
0 2 1
1 4 2
输出样例#1:
11

说明

每个格子中的数不超过100

【题解】

先把每个点拆成2个A,B,
Ai->Bi之间连2条边,一条流量为1,费用为该格点上的权值,以计算费用,
另一条流量为INF,费用为0,保证通路,再把每个点扫一遍,
可以到达的点之间Bi->Aj连流量INF,费用0的边。
虚拟源st=0,st->A1(第一个点)连费用0,流量k的边,限制流量。
虚拟汇ed=n*n*2+1,,右下角的格点Bi->ed连费用0,流量k的边。。。
跑一遍最大费用最大流就行了。。

#include<cstdio>
#include<iostream>
using namespace std;
const int N=110;
const int M=N*N;
const int inf=0x3f3f3f3f;
struct node{
    int v,next,cap,cost;
}e[M*50];int tot=1;
int n,m,k,S,T,ans,head[M],dis[M],pree[M],q[M*50];
bool vis[M];
void add(int x,int y,int cap,int cost){
    e[++tot].v=y;e[tot].cap=cap;e[tot].cost=cost;e[tot].next=head[x];head[x]=tot;
    e[++tot].v=x;e[tot].cap=0;e[tot].cost=-cost;e[tot].next=head[y];head[y]=tot;
}
bool spfa(){
    for(int i=S;i<=T;i++) vis[i]=0,dis[i]=-inf;
    int h=0,t=1;
    q[t]=S;dis[S]=0;vis[S]=1;
    while(h!=t){
        int x=q[++h];vis[x]=0;
        for(int i=head[x];i;i=e[i].next){
            int v=e[i].v;
            if(e[i].cap>0&&dis[v]<dis[x]+e[i].cost){
                dis[v]=dis[x]+e[i].cost;
                pree[v]=i;
                if(!vis[v]){
                    vis[v]=1;
                    q[++t]=v;
                }
            }
        }
    }
    return dis[T]>0;
}
void augment(){
    int tmp=inf;
    for(int i=T;i!=S;i=e[pree[i]^1].v){
        tmp=min(tmp,e[pree[i]].cap);
    }
    for(int i=T;i!=S;i=e[pree[i]^1].v){
        ans+=tmp*e[pree[i]].cost;
        e[pree[i]].cap-=tmp;
        e[pree[i]^1].cap+=tmp;
    }
}
int main(){
    scanf("%d%d",&n,&k);S=0;T=n*n*2+1;
    for(int i=1,now=1,plus=n*n,x;i<=n;i++){
        for(int j=1;j<=n;j++,now++){
            scanf("%d",&x);
            add(now,now+plus,1,x);
            add(now,now+plus,inf,0);
            if(j<n) add(now+plus,now+1,inf,0);
            if(i<n) add(now+plus,now+n,inf,0);
        }
    }
    add(S,S+1,k,0);
    add(T-1,T,k,0);
    while(spfa()) augment();
    printf("%d",ans);
    return 0;
}
原文地址:https://www.cnblogs.com/shenben/p/6260353.html