hdu 3657 最小割的活用 / 奇偶方格取数类经典题 /最小割

题意:方格取数,如果取了相邻的数,那么要付出一定代价。(代价为2*(X&Y))(开始用费用流,敲升级版3820,跪。。。)

建图:  对于相邻问题,经典方法:奇偶建立二分图。对于相邻两点连边2*(X&Y),源->X连边,Y->汇连边,权值w为点权。

ans=总点权-最小割:如果割边是源->X,表示x不要选(是割边,必然价值在路径上最小),若割边是Y-汇点,同理;若割边是X->Y,则表示选Y点且选X点, 割为w( 2*(X&Y) )。

自己的确还没有理解其本质精妙所在。不知何以然也。(开始多敲多了几个else一直跪!)

#include<iostream>
#include<queue>
#include<cstdio>
#include<cstring>
#include<set>
#include<vector>
using namespace std;
const int inf=0x3f3f3f3f;
const int maxv=2550,maxe=20000;
int nume=0;int head[maxv];int e[maxe][3];
void inline adde(int i,int j,int c)
{
    e[nume][0]=j;e[nume][1]=head[i];head[i]=nume;
    e[nume++][2]=c;
    e[nume][0]=i;e[nume][1]=head[j];head[j]=nume;
    e[nume++][2]=0;
}
int ss,tt,n,m,k;
int vis[maxv];int lev[maxv];
bool bfs()
{
    for(int i=0;i<maxv;i++)
      vis[i]=lev[i]=0;
    queue<int>q;
    q.push(ss);
    vis[ss]=1;
    while(!q.empty())
    {
        int cur=q.front();
        q.pop();
        for(int i=head[cur];i!=-1;i=e[i][1])
        {
            int v=e[i][0];
            if(!vis[v]&&e[i][2]>0)
            {
                lev[v]=lev[cur]+1;
                vis[v]=1;
                q.push(v);
            }
        }
    }
    return vis[tt];
}
int dfs(int u,int minf)
{
    if(u==tt||minf==0)return minf;
    int sumf=0,f;
    for(int i=head[u];i!=-1&&minf;i=e[i][1])
    {
        int v=e[i][0];
        if(lev[v]==lev[u]+1&&e[i][2]>0)
        {
            f=dfs(v,minf<e[i][2]?minf:e[i][2]);
            e[i][2]-=f;e[i^1][2]+=f;
            sumf+=f;minf-=f;
        }
    }
    if(!sumf) lev[u]=-1;
    return sumf;
}
int dinic()
{
    int sum=0;
    while(bfs())sum+=dfs(ss,inf);
    return sum;
};
int mapp[52][52];int must[maxv];int sums=0;
void read_build()
{
    for(int i=0;i<n;i++)
      for(int j=0;j<m;j++)
      {
        scanf("%d",&mapp[i][j]);
        sums+=mapp[i][j];
       }
     int aa,bb;
    for(int i=0;i<k;i++)
    {
        scanf("%d%d",&aa,&bb);
       must[(aa-1)*m+bb-1]=1;
    }
    for(int i=0;i<n;i++)
      for(int j=0;j<m;j++)
      {
         if((i+j)%2==0)
         {
             if(must[i*m+j])
              adde(ss,i*m+j,inf);
             else
              adde(ss,i*m+j,mapp[i][j]);
             if(i-1>=0)
                 adde(i*m+j,(i-1)*m+j,2*(mapp[i][j]&mapp[i-1][j]));
              if(i+1<n)
                adde(i*m+j,(i+1)*m+j,2*(mapp[i][j]&mapp[i+1][j]));
              if(j-1>=0)
                adde(i*m+j,i*m+j-1,2*(mapp[i][j]&mapp[i][j-1]));
              if(j+1<m)
                adde(i*m+j,i*m+j+1,2*(mapp[i][j]&mapp[i][j+1]));
         }
         else
         {
              if(must[i*m+j])
              adde(i*m+j,tt,inf);
             else
              adde(i*m+j,tt,mapp[i][j]);
         }
      }
  /*  for(int i=0;i<=tt;i++)
      for(int j=head[i];j!=-1;j=e[j][1])
      {
          if(j%2==0)
          printf("%d->%d:%d\n",i,e[j][0],e[j][2]);
      }*/
}
void init()
{
    nume=0;sums=0;
    ss=n*m+2;tt=ss+1;
    for(int i=0;i<=tt;i++)
      {
          head[i]=-1;
          must[i]=0;
      }
}
int main()
{
      while(scanf("%d%d%d",&n,&m,&k)!=EOF)
     {
         init();
        read_build();
       int ans;
       ans=sums-dinic();
      printf("%d\n",ans);
    }
    return 0;
}

hdu 3657 最小割的活用 / 奇偶方格取数类经典题 /最小割,布布扣,bubuko.com

时间: 2024-10-05 23:48:32

hdu 3657 最小割的活用 / 奇偶方格取数类经典题 /最小割的相关文章

hdu 4859 最大点权独立集的变形(方格取数的变形)

/*刚开始不会写,最大点权独立集神马都不知道,在潘神的指导下终于做出来,灰常感谢ps: 和方格取数差不多奇偶建图,对于D必割点权为0,对于.必然不割点权为inf.然后和方格取数差不多的建图 .--.||E权值为2,,.||E--D权值为0. 最大点权独立集=sum-最小点权覆盖. */ #include<stdio.h> #include<string.h> #include<queue> using namespace std; #define inf 0x3ffff

P2774 方格取数问题 网络最大流 割

P2774 方格取数问题:https://www.luogu.org/problemnew/show/P2774 题意: 给定一个矩阵,取出不相邻的数字,使得数字的和最大. 思路: 可以把方格分成两个部分,横坐标和纵坐标和为奇数的一组,和为偶数的一组,超级源点向偶数一组连容量为格点数字大小的边,奇数一组向超级汇点连容量为格点大小的边.然后两组间相临的点连容量为无穷的边. 跑出这个图的最大流,相当于是最小割,就是去掉了最少的部分使得网络不流通.因此答案就是sum - dinic(): #inclu

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

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

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

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

二分图最小点权覆盖 二分图最大权独立集 方格取数 最小割

二分图最小点权覆盖: 每一条边 (u, v) 都是一个限制条件, 要求 u 和 v 不能同时取得. 我们考虑先取得所有的, 然后减去最小的点权. 建立原点 S , 连向二分图左边的所有点, 与 S 连通的意义是左边的点被选择了, 或者右边的点没有被选择. 建立汇点 T , 二分图右边的所有点连向它, 与 T 连通的意义是左边的点没有被选择, 或者右边的点被选择了. 利用最小割最大流定理, 我们跑最大流, 再根据最后一次 BFS 得出的情报构造方案. 定理 覆盖集与独立集互补. 证明 即证明覆盖集

734. [网络流24题] 方格取数问题 二分图点权最大独立集/最小割/最大流

?问题描述:在一个有m*n 个方格的棋盘中,每个方格中有一个正整数.现要从方格中取数,使任意2 个数所在方格没有公共边,且取出的数的总和最大.试设计一个满足要求的取数算法.?编程任务:对于给定的方格棋盘,按照取数要求编程找出总和最大的数.?数据输入:由文件grid.in提供输入数据.文件第1 行有2 个正整数m和n,分别表示棋盘的行数和列数.接下来的m行,每行有n个正整数,表示棋盘方格中的数. [问题分析] 二分图点权最大独立集,转化为最小割模型,从而用最大流解决. [建模方法] 首先把棋盘黑白

LiberOJ #6007. 「网络流 24 题」方格取数 最小割 最大点权独立集 最大流

#6007. 「网络流 24 题」方格取数 内存限制:256 MiB时间限制:1000 ms标准输入输出 题目类型:传统评测方式:文本比较 上传者: 匿名 提交提交记录统计讨论测试数据 题目描述 在一个有 m×n m \times nm×n 个方格的棋盘中,每个方格中有一个正整数. 现要从方格中取数,使任意 2 22 个数所在方格没有公共边,且取出的数的总和最大.试设计一个满足要求的取数算法. 输入格式 文件第 1 11 行有 2 22 个正整数 m mm 和 n nn,分别表示棋盘的行数和列数

P2774 方格取数问题(最小割)

P2774 方格取数问题 一看题目便知是网络流,但由于无法建图.... 题目直说禁止那些条件,这导致我们直接建图做不到,既然如此,我们这是就要逆向思维,他禁止那些边,我们就连那些边. 我们将棋盘染色,一个点向四周连边,我们的目标是使的这些边不起作用,我们将黑点与s联通,白点与t联通. 之后我们就要考虑一个事情,只要一个黑点与白点由流,此时一定s到t有流.这样我们就能想到最小割... #include<bits/stdc++.h> #define ll long long using names