Luogu_P2045 方格取数加强版 最大费用最大流

Luogu_P2045 方格取数加强版

最大费用最大流


题目链接
费用流
把每个点都拆成两个点
两个点之间连一条费用为\(0\),流量为\(inf\)的边,一条费用为\(w\),流量为\(1\)
然后从源点和\((1,1)\)连一条流量为\(k\)费用为\(0\)的边
\((n,n)\)的第二个点到汇点也是流量为\(k\)费用为\(0\)的边。
相邻的点也是费用为\(0\),流量为\(inf\)的边
跑最大流最大费就好了
可以把边权建成负的,这样的最小费用就是最大费用的负数


代码如下:

#include<bits/stdc++.h>
using namespace std;
const int inf=0x3f3f3f3f;
int n,k,s,t,head[1100*1100],tot=1;
inline int wh(int x,int y){return (x-1)*n+y;}
struct node{
    int nxt,to,fl,wt;
    #define nxt(x) e[x].nxt
    #define to(x) e[x].to
    #define fl(x) e[x].fl
    #define wt(x) e[x].wt 
}e[1100*1100<<1];
inline void add(int from,int to,int fl,int wt){
    to(++tot)=to;fl(tot)=fl;wt(tot)=wt;nxt(tot)=head[from];head[from]=tot;
    to(++tot)=from;fl(tot)=0;wt(tot)=-wt;nxt(tot)=head[to];head[to]=tot;
}
int dis[11000],inq[11000];
inline bool spfa(){
    memset(dis,0x3f,sizeof(dis));memset(inq,0,sizeof(inq));
    queue<int> q;q.push(s);dis[s]=0;inq[s]=1;
    while(q.size()){
        int x=q.front();q.pop();inq[x]=0;
        for(int i=head[x];i;i=nxt(i)){
            int y=to(i);
            if(fl(i) && dis[y]>dis[x]+wt(i)){
                dis[y]=dis[x]+wt(i);
                if(!inq[y]){
                    inq[y]=1;q.push(y);
                }
            }
        }
    }
    return dis[t]<inf;
}
int dinic(int x,int dist){
    int res=dist;
    if(x==t || dist<=0) return dist;
    inq[x]=1;
    for(int i=head[x];i;i=nxt(i)){
        int y=to(i);
        if(!inq[y] && dis[y]==dis[x]+wt(i) && fl(i)){
            int k=dinic(y,min(res,fl(i)));
            res-=k;fl(i)-=k;fl(i^1)+=k;
            if(!res) break;
        }
    }
    return dist-res;
}
int main()
{
    scanf("%d%d",&n,&k);
    s=0,t=2*n*n+1;
    add(s,wh(1,1),k,0);add(wh(n,n)+n*n,t,k,0);
    for(int i=1;i<=n;i++) for(int j=1;j<=n;j++){
        int x;scanf("%d",&x);
        add(wh(i,j),wh(i,j)+n*n,1,-x);add(wh(i,j),wh(i,j)+n*n,inf,0);
        if(i<n) add(wh(i,j)+n*n,wh(i+1,j),inf,0);
        if(j<n) add(wh(i,j)+n*n,wh(i,j+1),inf,0);
    }
    int d=0,ans=0;
    while(spfa())
        while(d=dinic(s,inf),d!=0) memset(inq,0,sizeof(inq)),ans+=d*dis[t];
    printf("%d\n",-ans);
    return 0;
}
posted @ 2019-10-15 15:02  ChrisKKK  阅读(92)  评论(0编辑  收藏  举报