【网络流】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[v] = ct++;
}
--------------------------------------
memset(p,-1,sizeof(p);???????
--------------------------------------
for(int i=first[u]; i!=-1; i=next[i])
{
    if(!a[e[i].v]&&e[i].f)找新结点e[i].v
    {
        p[e[i].v]=i;记录e[i].v的父亲
        a[e[i].v]=min(a[u],e[i].f);s-e[i].v路径上的最小残量和
        q.push(e[i].v);父亲加入队列
    }
}
--------------------------------------
for(int u=t; u!=s; u=e[p[u]].u)从汇点往回用走
{
    e[p[u]].f-=a[t];
    e[p[u]^1].f+=a[t];异或的作用
}
--------------------------------------
建图,题目的关键。。用奇偶建立二分图
代码理解:
for(int i=1; i<=m; i++)
{
    for(int j=1; j<=n; j++)
    {
        int tmp=(i-1)*n+j;格子从1.....n*m编号,tmp是格子的编号
        if((i+j)%2==0)偶数
        {
            add(s,tmp,g[i][j]);与源点相连
            if(i>1)
                add(tmp,(i-2)*n+j,INF);
            if(i<m)
                add(tmp,i*n+j,INF);
            if(j>1)
                add(tmp,(i-1)*n+j-1,INF);
            if(j<n)
                add(tmp,(i-1)*n+j+1,INF);
        }
        else
            add(tmp,t,g[i][j]);与汇点
    }
}
---------------------------------
*/
#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>
#define INF 0x3f3f3f3f

    using namespace std;

    struct node
    {
        int u,v,f;
    } e[60000];

    int n,m;
    int p[3000];
    int first[3000],next[60000],ct;
    int g[55][55];
    int a[3000];
    int sum;
    int s,t;

    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[v] = ct++;
    }

    int EK(int s, int t)
    {
        queue<int> q;
        int f=0;
        while(1)
        {
            memset(a,0,sizeof(a));
            memset(p,-1,sizeof(p));
            q.push(s);
            a[s]=INF;
            while(!q.empty())
            {
                int u=q.front();
                q.pop();
                for(int i=first[u]; i!=-1; i=next[i])
                {
                    if(!a[e[i].v]&&e[i].f)
                    {
                        p[e[i].v]=i;
                        a[e[i].v]=min(a[u],e[i].f);
                        q.push(e[i].v);
                    }
                }
            }
            if(a[t]==0)
                break;
            for(int u=t; u!=s; u=e[p[u]].u)
            {
                e[p[u]].f-=a[t];
                e[p[u]^1].f+=a[t];
            }
            f+=a[t];
        }
        return f;
    }

    void init()
    {
        sum = 0;
        ct = 0;
        memset(first,-1,sizeof(first));
        memset(next,-1,sizeof(next));
        for(int i=1; i<=m; i++)
        {
            for(int j=1; j<=n; j++)
            {
                scanf("%d",&g[i][j]);
                sum += g[i][j];
            }
        }
        for(int i=1; i<=m; i++)
        {
            for(int j=1; j<=n; j++)
            {
                int tmp=(i-1)*n+j;
                if((i+j)%2==0)
                {
                    add(s,tmp,g[i][j]);
                    if(i>1)
                        add(tmp,(i-2)*n+j,INF);
                    if(i<m)
                        add(tmp,i*n+j,INF);
                    if(j>1)
                        add(tmp,(i-1)*n+j-1,INF);
                    if(j<n)
                        add(tmp,(i-1)*n+j+1,INF);
                }
                else
                    add(tmp,t,g[i][j]);
            }
        }
    }

    int main()
    {
        //freopen("input.txt","r",stdin);
        while(scanf("%d%d",&m,&n) != EOF)
        {
            s=0;
            t=n*m+1;
            init();
            printf("%d\n",sum - EK(s, t));
        }
        return 0;
    }

---------------------------------------------------------------------

。。。。。。。。。。。。。。。。。。。。。。。。

【网络流】hdu 1569 方格取数(2),布布扣,bubuko.com

时间: 2024-10-19 19:32:52

【网络流】hdu 1569 方格取数(2)的相关文章

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 1565] 方格取数(1)

方格取数(1) Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 5961    Accepted Submission(s): 2268 Problem Description 给你一个n*n的格子的棋盘,每个格子里面有一个非负数.从中取出若干个数,使得任意的两个数所在的格子没有公共边,就是说所取的数所在的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 1569 方格取数(2)

方格取数(2) Time Limit: 5000ms Memory Limit: 32768KB This problem will be judged on HDU. Original ID: 156964-bit integer IO format: %I64d      Java class name: Main 给你一个m*n的格子的棋盘,每个格子里面有一个非负数.从中取出若干个数,使得任意的两个数所在的格子没有公共边,就是说所取数所在的2个格子不能相邻,并且取出的数的和最大. Inpu

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

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

HDU 1569 方格取数(2)(最小割)

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

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

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

HDU 1569 - 方格取数(2) - [最大点权独立集与最小点权覆盖集]

嗯,这是关于最大点权独立集与最小点权覆盖集的姿势,很简单对吧,然后开始看题. HDU1569: Time Limit: 10000/5000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others) Problem Description 给你一个m*n的格子的棋盘,每个格子里面有一个非负数.从中取出若干个数,使得任意的两个数所在的格子没有公共边,就是说所取数所在的2个格子不能相邻,并且取出的数的和最大. Input 包括多个测试实例,

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

题意:给出一个n*m的矩阵,求选出若干个互不不相邻 的数,使得和最大 分析:刘汝佳白书给出求带权二分图的最大独立集解法.即每个节点有一个权值,要求选出一些节点,互不相邻,且权值最大 加入一个源点s和一个汇点t,使得s向其中一个集合的点连一条边,容量为该点的权值,另一部分的点向t连一条边,容量为该点的权值,原来的边容量为INF,求图的一个割,将割对应的边删掉就是要求的解,权和为所有权减去割的容量 #include<bits/stdc++.h> using namespace std; const