P2045 方格取数加强版

题目描述

给出一个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

说明/提示

每个格子中的数不超过1000

思路

拆点+最大流费用最大流

代码

#include<bits/stdc++.h>
#define N 107000
#define M 107000
#define inf 1<<29
using namespace std;
struct node{
    int y,z,p,next;
}e[M*2];
int tot=1,head[N],maxflow=0,ans=0,s,t;
void add(int x,int y,int z,int p){
    e[++tot].y=y;e[tot].z=z;e[tot].p=p;
    e[tot].next=head[x];head[x]=tot;
}
int incf[N],v[N],pre[N],d[N];
bool spfa(){
    queue<int> q;
    memset(d,0xcf,sizeof(d));
    memset(v,0,sizeof(v));
    q.push(s);d[s]=0;v[s]=1;
    incf[s]=inf;
    while(q.size()){
        int x=q.front();v[x]=0;q.pop();
        for(int i=head[x];i;i=e[i].next){
            int y=e[i].y,z=e[i].z;
            if(!z) continue;
            if(d[y]<d[x]+e[i].p){
                d[y]=d[x]+e[i].p;
                incf[y]=min(incf[x],z);
                pre[y]=i;
                if(!v[y]) v[y]=1,q.push(y);
            }
        }
    }
    if(d[t]==0xcfcfcfcf) return false;
    return true;
}
void update(){
    int x=t;
    while(x!=s){
        int i=pre[x];
        e[i].z-=incf[t];
        e[i^1].z+=incf[t];
        x=e[i^1].y; 
    }
    maxflow+=incf[t];
    ans+=d[t]*incf[t];
}
int gcd(int a,int b){
    return b==0?a:gcd(b,a%b);
}
int f(int x,int y){
    int k=x*x-y*y;
    int g=sqrt(k);
    if(g*g==k&&gcd(y,g)==1) return 1;
    else return 0;
}
int n,k;
int num(int a,int b){
    return (a-1)*n+b;
}
int a[60][60];
#define MAXN 3000
int main(){
    cin>>n>>k;
    s=num(1,1);t=num(n,n)+MAXN;
    for(int i=1;i<=n;i++)
        for(int j=1;j<=n;j++)
            scanf("%d",&a[i][j]);
    for(int i=1;i<=n;i++){
        for(int j=1;j<=n;j++){
            add(num(i,j),num(i,j)+MAXN,1,a[i][j]);add(num(i,j)+MAXN,num(i,j),0,-a[i][j]);
            add(num(i,j),num(i,j)+MAXN,k-1,0); add(num(i,j)+MAXN,num(i,j),0,0);
            if (i+1<=n) add(num(i,j)+MAXN,num(i+1,j),k,0),add(num(i+1,j),num(i,j)+MAXN,0,0);
            if (j+1<=n) add(num(i,j)+MAXN,num(i,j+1),k,0),add(num(i,j+1),num(i,j)+MAXN,0,0);
        }
    }
    while(spfa()) 
        update();
    cout<<ans<<endl;
    return 0;
}
原文地址:https://www.cnblogs.com/wangyiding2003/p/11530368.html