zoukankan      html  css  js  c++  java
  • 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
    ",-ans);
        return 0;
    }
    
  • 相关阅读:
    ResponsibleChain(责任链模式)
    IteratorPattern(迭代子模式)
    为什么抽象类不能实例化却有构造方法
    ObserverPattern(观察者模式)
    TemplateMethod(模块方法模式)
    java 定义一个同步map内存去重法
    oracle sql修改序列为当前序列开始
    oracle sql 当初始化数据时避免重复主键
    搭建基于express框架运行环境
    vue路由基础介绍
  • 原文地址:https://www.cnblogs.com/ChrisKKK/p/11677734.html
Copyright © 2011-2022 走看看