Vijos1653 疯狂的方格取数(MCMF)

Posted xxrlz

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Vijos1653 疯狂的方格取数(MCMF)相关的知识,希望对你有一定的参考价值。

  • 题意: 给出一个方格取数,最多能取k次,问最多能取到多少
  • 思路: 最大费用最大流
#include<cstring>
#include<iostream>
#include<algorithm>
#include<queue>
#include<vector>
#include<set>
#include<cmath>
#include<stack>
#define ll long long
using namespace std;
typedef  pair<int,int> pii;

const int N = 1e5+10;
const int INF = 0x3f3f3f3f;


struct E
    int u,v,flow,nxt,w;
    E()
    E(int u,int v,int flow,int nxt,int w):u(u),v(v),flow(flow),nxt(nxt),w(w)
e[N*2];

int n,m,k,sp,tp,tot;
int head[N],dis[N],pre[N],cur[N],vis[N];
ll cost;
void init()
    tot = 0;    memset(head,-1,sizeof head);

void addE(int u,int v,int flow,int cost)
    e[tot].u = u; e[tot].v = v; e[tot].flow = flow; e[tot].nxt = head[u]; e[tot].w = cost; head[u] = tot++;
    e[tot].u = v; e[tot].v = u; e[tot].flow = 0; e[tot].nxt = head[v]; e[tot].w = -cost; head[v] = tot++;

int q[N];
int bfs()
    int qtop = 0,qend=0;
    memset(vis,0,sizeof vis);
    memset(dis,0x3f,sizeof dis);  
    dis[sp] = 0;    
    q[qend++] = sp;
    while(qtop!=qend)
        int u = q[qtop++];
        vis[u] = 0;
        // if(u==tp)   return true;
        for(int i=head[u];~i;i=e[i].nxt)
            int v = e[i].v;
            if(dis[v]>dis[u]+e[i].w && e[i].flow)
                dis[v] = dis[u]+e[i].w;
                if(!vis[v])  
                    q[qend++] = v,vis[v] = 1;
            
        
    
    return dis[tp]!= INF;

int dfs(int u,int flow)
    int res = 0;
    if(u==tp)   return flow;
    vis[u] = 1;
    for(int i=head[u];i!=-1&&flow;i=e[i].nxt)
        int v = e[i].v;
        if(!vis[v] && dis[v]==dis[u]+e[i].w && e[i].flow)
            int d = dfs(v,min(e[i].flow,flow));
            e[i].flow -=d;
            e[i^1].flow += d;
            res+=d;
            flow -= d;
            cost += d*e[i].w;
        
    
    vis[u] = 0;
    if(!res)
        dis[u] = -2;
    return res;

int dinic()
    int ans=0;
    while(bfs())
        ans+=dfs(sp,INF);
    
    return ans;

int main()
    scanf("%d%d%d",&k,&m,&n);
    init();
    sp = n*m*2+1,tp = sp + 1;
    int cp,val,step = n*m;
    for(int i=1;i<=n;++i)
        for(int j=1;j<=m;++j)
            scanf("%d",&val);
            cp = (i-1)*m + j;
            addE(cp,cp+step,1,-val);    // 流量为1,每个点只能被取一次
            addE(cp,cp+step,k,0);       // 流量为k,可以经过k次
            if(i<n)
                addE(cp+step,(cp+m),k,0);   // 向下走
            
            if(j<m)
                addE(cp+step,(cp+1),k,0);   // 向右走
            
        
    
    addE(sp,1,k,0);
    addE(n*m+step,tp,k,0);
    dinic();
    printf("%lld\n",-cost); // 边权取反,求mcmf,最后答案取反
    return 0;

题目

以上是关于Vijos1653 疯狂的方格取数(MCMF)的主要内容,如果未能解决你的问题,请参考以下文章

方格取数问题 最小割

网络流 24题 方格取数

方格取数问题 线性规划网络流

P2774 方格取数问题

网络流24题方格取数问题

方格取数(网络流24题)