拆点后入点和出点两条(容量,边权)为的边
求解最大流需要寻找所以一条增广路,为了费用之和最小,可以改用spfa寻找一条单位费用之和最小的增广路,每次在残余网络中跑最长路,直到找到最大流。
这题不要求最大流,所以如果残余网络中得不到费用后可以直接退出。

MyCode:

#include <bits/stdc++.h>
using namespace std;
const int maxn=5010,maxm=200010;
typedef long long int ll;

int head[maxn],Next[maxm],to[maxm],edge[maxm],tot=1,d[maxn],s,t,now[maxn],n,k;
int pre[maxn],incf[maxn],cost[maxm];
void add(int x,int y,int z,int c) {
    to[++tot]=y; Next[tot]=head[x]; head[x]=tot; edge[tot]=z; cost[tot]=c;
    to[++tot]=x; Next[tot]=head[y]; head[y]=tot; edge[tot]=0; cost[tot]=-c;
}
inline int num(int x,int y,int k) {
    return (x-1)*n+y+k*n*n;
}
queue<int>que;
bool vis[maxn];
bool spfa() {
    while(que.size()) que.pop();
    memset(d,0xcf,sizeof(d));//-inf
    memset(vis,0,sizeof vis);
    que.push(s); d[s]=0; vis[s]=1;
    int x,y; incf[s]=0x3f3f3f3f;
    while(que.size()) {
        x=que.front(); que.pop(); vis[x]=0;
        for(int i=head[x],y=to[i];i;i=Next[i],y=to[i]) {
            if(!edge[i]) continue;
            if(d[y]<d[x]+cost[i]) {
                d[y]=d[x]+cost[i];
                incf[y]=min(incf[x],edge[i]);//最小流量 
                pre[y]=i;//记录前驱 
                if(!vis[y]) {
                    que.emplace(y); vis[y]=1;
                }
            }
        }
    }
    if(d[t]==0xcfcfcfcf) return false;
    return true;
}
void update(int &ans) {
    int x=t,i;
    while(x!=s) {
        i=pre[x];
        edge[i]-=incf[t];
        edge[i^1]+=incf[t];
        x=to[i^1];
    }
//    maxflow+=incf[t];
    ans+=d[t]*incf[t];
}
int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    cin>>n>>k;
    s=1,t=2*n*n;
    for(int i=1,c;i<=n;++i)
    for(int j=1;j<=n;++j) {
        cin>>c;
        add(num(i,j,0),num(i,j,1),1,c);    add(num(i,j,0),num(i,j,1),k-1,0);
        if(i<n) add(num(i,j,1),num(i+1,j,0),k,0);
        if(j<n) add(num(i,j,1),num(i,j+1,0),k,0);
    }
    int ans(0);
    while(spfa()) update(ans);
    cout<<ans<<'\n';
}