hdu 1569 最大流

擦,搞了几个模板,都有错,就这个还好吧
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <climits>
#include <vector>
#include <queue>
#include <cstdlib>
#include <string>
#include <set>
#include <stack>
#define LL long long
#define pii pair<int,int>
#define INF 0x3f3f3f3f
using namespace std;
const int maxn = 3000;
struct arc {
    int to,flow,next;
    arc(int x = 0,int y = 0,int z = 0) {
        to = x;
        flow = y;
        next = z;
    }
};
arc e[maxn*10];
int head[maxn],d[maxn],tot;
int S,T,q[maxn],hd,tail,n,m;
void add(int u,int v,int flow) {
    e[tot] = arc(v,flow,head[u]);
    head[u] = tot++;
    e[tot] = arc(u,0,head[v]);
    head[v] = tot++;
}
bool bfs() {
    for(int i = 1; i <= T; i++) d[i] = 0;
    d[S] = 1;
    hd = tail = 0;
    q[tail++] = S;
    while(hd < tail) {
        int u = q[hd++];
        for(int i = head[u]; ~i; i = e[i].next) {
            if(e[i].flow && !d[e[i].to]) {
                d[e[i].to] = d[u]+1;
                q[tail++] = e[i].to;
            }
        }
    }
    return d[T];
}
int dfs(int u,int low) {
    int tmp = 0,f;
    if(u == T || !low) return low;
    for(int i = head[u]; ~i; i = e[i].next) {
        if(d[e[i].to] == d[u]+1 && (f = dfs(e[i].to,min(low,e[i].flow)))) {
            tmp += f;
            e[i].flow -= f;
            e[i^1].flow += f;
            low -= f;
            if(!low) break;
        }
    }
    return tmp;
}
void init(){
    memset(head,-1,sizeof(head));
    tot = 0;
}
int main(){
   while(scanf("%d%d", &m,&n) != EOF)
    {
        init();
        int x;
        int sum = 0;
        S = 0;
        T = m * n + 1;
        for(int i = 1; i <= m; ++ i)
            for(int j = 1; j <= n; ++ j)
            {
                scanf("%d", &x);
                sum += x;
                if((i + j) & 1)
                {
                    add(S, (i - 1) * n + j, x);
                    //上
                    if(i > 1)  add((i - 1) * n + j, (i - 2) * n + j, INF);
                    //下
                    if(i < m)  add((i - 1) * n + j, i * n + j, INF);
                    //左
                    if(j > 1)  add((i - 1) * n + j, (i -1) * n + j - 1, INF);
                    //右
                    if(j < n)  add((i - 1) * n + j, (i - 1) * n + j + 1, INF);
                }
                else
                     add((i - 1) * n + j, T, x);
            }
            int ans = 0;
            while(bfs())ans+=dfs(S,INF);
            printf("%d\n",sum - ans);
    }
}

原来边就有权值的:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <climits>
#include <vector>
#include <queue>
#include <cstdlib>
#include <string>
#include <set>
#include <stack>
#define LL long long
#define pii pair<int,int>
#define INF 0x3f3f3f3f
using namespace std;
const int maxn = 3000;
struct arc {
    int to,cap,flow,next;
    arc(int x= 0 ,int y=0 ,int z=0 ,int u=0) {
        to = x;
        cap = y;
        flow = z;
        next = u;
    }
};
arc e[maxn*10];
int head[maxn],d[maxn],tot;
int S,T,q[maxn],hd,tail,n,m;
void add(int u,int v,int cap,int flow) {
    e[tot] = arc(v,cap,flow,head[u]);
    head[u] = tot++;
    e[tot] = arc(u,0,-flow,head[v]);
    head[v] = tot++;
}
bool bfs() {
    for(int i = 1; i <= T; i++) d[i] = 0;
    d[S] = 1;
    hd = tail = 0;
    q[tail++] = S;
    while(hd < tail) {
        int u = q[hd++];
        for(int i = head[u]; ~i; i = e[i].next) {
            if(e[i].cap > e[i].flow && !d[e[i].to]) {
                d[e[i].to] = d[u]+1;
                q[tail++] = e[i].to;
            }
        }
    }
    return d[T];
}
int dfs(int u,int low) {
    int tmp = 0,f;
    if(u == T || !low) return low;
    for(int i = head[u]; ~i; i = e[i].next) {
        if(d[e[i].to] == d[u]+1 && (f = dfs(e[i].to,min(low,e[i].cap-e[i].flow)))) {
            tmp += f;
            e[i].flow += f;
            e[i^1].flow -= f;
            low -= f;
            if(!low) break;
        }
    }
    return tmp;
}
void init(){
    memset(head,-1,sizeof(head));
    tot = 0;
}
int main(){
   while(scanf("%d%d", &m,&n) != EOF)
    {
        init();
        int x;
        int sum = 0;
        S = 0;
        T = m * n + 1;
        for(int i = 1; i <= m; ++ i)
            for(int j = 1; j <= n; ++ j)
            {
                scanf("%d", &x);
                sum += x;
                if((i + j) & 1)
                {
                    add(S, (i - 1) * n + j, x,0);
                    //上
                    if(i > 1)  add((i - 1) * n + j, (i - 2) * n + j, INF,0);
                    //下
                    if(i < m)  add((i - 1) * n + j, i * n + j, INF,0);
                    //左
                    if(j > 1)  add((i - 1) * n + j, (i -1) * n + j - 1, INF,0);
                    //右
                    if(j < n)  add((i - 1) * n + j, (i - 1) * n + j + 1, INF,0);
                }
                else
                     add((i - 1) * n + j, T, x,0);
            }
            int ans = 0;
            while(bfs())ans+=dfs(S,INF);
            printf("%d\n",sum - ans);
    }
}
时间: 2024-12-28 13:03:51

hdu 1569 最大流的相关文章

hdu 1565&amp;hdu 1569(网络流--最小点权值覆盖)

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

Leapin&#39; Lizards (hdu 2732 最大流)

Leapin' Lizards Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 1433    Accepted Submission(s): 586 Problem Description Your platoon of wandering lizards has entered a strange room in the labyr

HDU 1565 &amp;&amp; HDU 1569 方格取数 (网络流之最小割)

题目地址:HDU 1565       HDU 1569 刚开始接触最小割,就已经感受到了最小割的博大精深... 这建图思路倒是好想..因为好多这种关于不相邻的这种网络流都是基本都是这样建图.但是感觉毫无道理可言...看了题解后才明白这样做的意义. 下面是题解中的说法. 大概是这样分析的,题义是要我们求在一个方格内取出N个点,使得这N个独立的(不相邻)点集的和最大.我们可以将问题转化为最小割来求解.首先,我们将方格进行黑白相间的染色,然后再将任意一种颜色(黑色)作为源点,一种颜色(白色)作为汇点

【网络流】hdu 1569 方格取数(2)

/* 和1565一样: 总点数的权 - 最小覆盖点集 = 最大独立集 -------------------------------------- void add(int u, int v, int f)加边 { e[ct].u = u; e[ct].v = v; e[ct].f = f; next[ct] = first[u]; first[u] = ct++; e[ct].u = v; e[ct].v = u; e[ct].f = 0; next[ct] = first[v]; first

hdu 4888 最大流给出行列和求矩阵

第一步,考虑如何求是否有解.使用网络流求解,每一行和每一列分别对应一个点,加上源点和汇点一共有N+M+2个点.有三类边: 1. 源点 -> 每一行对应的点,流量限制为该行的和 2. 每一行对应的点 -> 每一列对应的点,流量限制为 K 3. 每一列对应的点 -> 汇点,流量限制为该列的和 对上图做最大流,若源点出发的边和到达汇点的边全都满流,则有解,否则无解.若要求构造方案,则 (i,j) 对应的整数就是行 i–> 列 j 的流量. 第二步,考虑解是否唯一.显然,解唯一的充分必要条

hdu 4975最大流与4888类似但是有很吊的优化最大流

//来自潘神的优化 #include<stdio.h> #include<string.h> #include<queue> using namespace std; #define inf 0x3fffffff #define N 1100 struct node { int u,v,w,next; }bian[N*N*4]; int head[N],yong,dis[N],work[N]; void init(){ yong=0; memset(head,-1,si

hdu 1569 方格取数(2)再解

上次我说用STL超时了,而用数组为0ms,其实不然,这个题STL依然不超时,代码如下 #include<map> #include<set> #include<stack> #include<queue> #include<cmath> #include<vector> #include<cstdio> #include<string> #include<cstring> #include<c

hdu 2686 费用流 / 双线程DP

题意:给一个方阵,求从左上角出到右下角(并返回到起点),经过每个点一次不重复,求最大获益(走到某处获得改点数值),下来时每次只能向右或向下,反之向上或向左. 俩种解法: 1  费用流法:思路转化:从左上角流出2的流量,(表示走俩条路),归于右下角,可以走就有边(右和下),权为负的费用,源点连起点,汇点连终点,流量为2. 除源汇外所有点一分为2,Y向X对应点有流量1的边,之前边为X到Y的(原图),这样处理解决每个点只最多走一次(除了源汇外)(X部只出,Y部要出必先回到X对应点).跑最小费用最大流即

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个格子不能相邻,并且取出的