【Luogu】P2045方格取数加强版(最小费用最大流)

  题目链接

  通过这题我学会了引诱算法的行为,就是你通过适当的状态设计,引诱算法按照你想要它做的去行动,进而达到解题的目的。

  最小费用最大流,首先将点拆点,入点和出点连一条费用=-权值,容量=1的边,再连费用=0,容量=INF的边,跑最小费用最大流即可。

  

#include<cstdio>
#include<cctype>
#include<algorithm>
#include<cstring>
#include<cstdlib>
#include<queue>
#define maxn 10000
#define maxm 500000
using namespace std;

inline long long read(){
    long long num=0,f=1;
    char ch=getchar();
    while(!isdigit(ch)){
        if(ch=='-')    f=-1;
        ch=getchar();
    }
    while(isdigit(ch)){
        num=num*10+ch-'0';
        ch=getchar();
    }
    return num*f;
}

int count(int i){    return i&1?i+1:i-1;    }
int calc(int i,int j,int n){    return (i-1)*n+j;    }

struct Edge{
    int from,next,to,val,flow,dis;
}edge[maxm];
int head[maxn],num;
inline void addedge(int from,int to,int val,int dis){
    edge[++num]=(Edge){from,head[from],to,val,0,dis};
    head[from]=num;
}
inline void add(int from,int to,int val,int dis){
    addedge(from,to,val,dis);
    addedge(to,from,0,-dis);
}

bool vis[maxn];
int dst[maxn];
int flow[maxn];
int pre[maxn];
int Start,End;

int spfa(){
    memset(vis,0,sizeof(vis));
    memset(dst,127/3,sizeof(dst));
    queue<int>q;    q.push(Start);    dst[Start]=0;    flow[Start]=0x7fffffff;
    while(!q.empty()){
        int from=q.front();    q.pop();    vis[from]=0;
        for(int i=head[from];i;i=edge[i].next){
            int to=edge[i].to;
            if(dst[to]<=dst[from]+edge[i].dis||edge[i].val<=edge[i].flow)    continue;
            pre[to]=i;
            dst[to]=dst[from]+edge[i].dis;
            //printf("%d %d %d\n",from,to,dst[to]);
            flow[to]=min(flow[from],edge[i].val-edge[i].flow);
            if(vis[to])    continue;
            vis[to]=1;    q.push(to);
        }
    }
    if(dst[End]==dst[End+1])    return 0;
    int now=End;
    while(now!=Start){
        int ret=pre[now];
        edge[ret].flow+=flow[End];    edge[count(ret)].flow-=flow[End];
        now=edge[ret].from;
    }
    return dst[End];
}

int q[maxn][maxn];

int main(){
    int n=read(),k=read();    End=maxn-10;
    for(int i=1;i<=n;++i)
        for(int j=1;j<=n;++j){
            q[i][j]=read();
            add(calc(i,j,n),calc(i,j,n)+n*n,1,-q[i][j]);
            add(calc(i,j,n),calc(i,j,n)+n*n,0x7fffffff,0);
        }
    for(int i=1;i<=n;++i)
        for(int j=1;j<=n;++j){
            if(i^n)    add(calc(i,j,n)+n*n,calc(i+1,j,n),0x7fffffff,0);
            if(j^n)    add(calc(i,j,n)+n*n,calc(i,j+1,n),0x7fffffff,0);
        }
    add(Start,calc(1,1,n),0x7fffffff,0);
    add(calc(n,n,n)+n*n,End,0x7fffffff,0);
    int ans=0;
    for(int i=1;i<=k;++i)    ans+=-spfa();
    printf("%d",ans);
}

 

posted @ 2018-01-19 17:05  Konoset  阅读(132)  评论(0编辑  收藏  举报