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;
}

题目

原文地址:https://www.cnblogs.com/xxrlz/p/11617836.html

时间: 2024-11-29 06:53:42

Vijos1653 疯狂的方格取数(MCMF)的相关文章

vijos 1563 疯狂的方格取数

P1653疯狂的方格取数 Accepted 标签:天才的talent[显示标签] 背景 Due to the talent of talent123,当talent123做完NOIP考了两次的二取方格数和vijos中的三取方格数后,突发奇想.... 描述 在一个宽M,长N的矩阵中,请你编一个程序,n次从矩阵的左上角走到矩阵的右下角,每到一处,就取走该处的数字,请你选择一种走法使取得的数字的和最大,并输出其最大值.其中:3<=M<=20 M<=N<=100 1<=n<=1

NEU 1458 方格取数(网络流之费用流)

题目地址:NEU 1458 跟杭电上的那两个方格取数不太一样..这个可以重复,但是取和的时候只能加一次.建图思路基本一会就出来.同样的拆点,只不过这题需要再拆个边,其中一条费用0,另一条费用为那个点处的值.流量都限制为1.然后剩下的都跟杭电上的那两个差不多了.因为把数组开小了WA了好几发..(我前面居然还专门检查了一下数组大小,居然当时还认为没开小...对自己无语..) 代码如下: #include <iostream> #include <stdio.h> #include &l

hdu 1565 方格取数(2)(网络流之最大点权独立集)

题目链接:hdu 1565 方格取数(2) 题意: 有一个n*m的方格,每个方格有一个数,现在让你选一些数.使得和最大. 选的数不能有相邻的. 题解: 我们知道对于普通二分图来说,最大独立点集 + 最小点覆盖集 = 总点数,类似的,对于有权的二分图来说,有: 最大点权独立集 + 最小点权覆盖集 = 总点权和, 这个题很明显是要求 最大点权独立集 ,现在 总点权 已知,我们只要求出来 最小点权覆盖集 就好了,我们可以这样建图, 1,对矩阵中的点进行黑白着色(相邻的点颜色不同),从源点向黑色的点连一

P1004 方格取数

P1004 方格取数 题目描述 设有N*N的方格图(N<=9),我们将其中的某些方格中填入正整数,而其他的方格中则放 人数字0.如下图所示(见样例): A 0 0 0 0 0 0 0 0 0 0 13 0 0 6 0 0 0 0 0 0 7 0 0 0 0 0 0 14 0 0 0 0 0 21 0 0 0 4 0 0 0 0 15 0 0 0 0 0 0 14 0 0 0 0 0 0 0 0 0 0 0 0 0 0 . B 某人从图的左上角的A点出发,可以向下行走,也可以向右走,直到到达右下角

hdoj 1569 方格取数(2) 【最小割】 【最大点权独立集】

方格取数(2) Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 5589    Accepted Submission(s): 1741 Problem Description 给你一个m*n的格子的棋盘,每个格子里面有一个非负数. 从中取出若干个数,使得任意的两个数所在的格子没有公共边,就是说所取数所在的2个格子不能相邻,并且取出的

1475: 方格取数

1475: 方格取数 Time Limit: 5 Sec  Memory Limit: 64 MBSubmit: 578  Solved: 309[Submit][Status][Discuss] Description 在一个n*n的方格里,每个格子里都有一个正整数.从中取出若干数,使得任意两个取出的数所在格子没有公共边,且取出的数的总和尽量大. Input 第一行一个数n:(n<=30) 接下来n行每行n个数描述一个方阵 Output 仅一个数,即最大和 Sample Input 2 1 2

hdu 1569 方格取数(2) 网络流 最大点权独立集

方格取数(2) Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 5146    Accepted Submission(s): 1610 Problem Description 给你一个m*n的格子的棋盘,每个格子里面有一个非负数. 从中取出若干个数,使得任意的两个数所在的格子没有公共边,就是说所取数所在的2个格子不能相邻,并且取出的

HDU 1565 方格取数(1) (状态压缩 DP)

方格取数(1) Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 5779    Accepted Submission(s): 2194 Problem Description 给你一个n*n的格子的棋盘,每个格子里面有一个非负数. 从中取出若干个数,使得任意的两个数所在的格子没有公共边,就是说所取的数所在的2个格子不能相邻,并且取出

HDU 1565 方格取数(1)(状压dp)

感觉这道题目的数据比较水啊,程序的时间复杂度为1711^2*20竟然也可以过掉....其他的就是状压了啊,注意需要滚动一下啊.... 方格取数(1) Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 5701    Accepted Submission(s): 2159 Problem Description 给你一个n*n的格子的棋