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

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1569

 

题目大意:给你一个m*n的格子的棋盘,每个格子里面有一个非负数。
            从中取出若干个数,使得任意的两个数所在的格子没有公共边,就是说所取数所在的2个格子不能相邻,并且取出的数的和最大。

 

解题思路:说实话,这样的网络流构图真的难想到,唉,练得太少了。

定理: 最大点独立集=sum-最小点覆盖集。

         这里要我们求最大点独立集,由上面的定理我们就可以转换为求最小点覆盖集。我发现网上很多题解对于割这一块讲解的不知所云,可能是对割的理解还没深入吧,不会就看别人解题报告,然后自己按照自己的理解不知所云的讲。 这题可以用类似国际象棋黑白棋的方法解,每个点和它周围四个点连一条容量为无穷的边,源点和黑点(奇数点)相连,汇点和白点(偶数点)相连,剩下的就看你怎么割了,应该是这么割的:割掉最少最小的边,使得从源点的流量一点都不能到达汇点 ,等价于求源点到汇点的最大流。

        建好图直接上模板,此刻顿时变成渣渣题了。

 

View Code
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;

const int mn=3333;
const int mm=1000000;
const int oo=0x3fffffff;
int node, st, sd, edge;
int flow[mm], reach[mm], next[mm];
int head[mn], work[mn], dis[mn], que[mn];

void init(int node_, int st_, int sd_)
{
    node=node_, st=st_, sd=sd_;
    for(int i=0; i<node; i++) head[i]=-1;
    edge=0;
}

void addedge(int u, int v, int c1, int c2)
{
    reach[edge]=v, flow[edge]=c1,  next[edge]=head[u], head[u]=edge++;
    reach[edge]=u, flow[edge]=c2,  next[edge]=head[v], head[v]=edge++;
}

bool bfs()
{
    int u, v, l=0, h=0;
    for(int i=0; i<node; i++) dis[i]=-1;
    que[l++]=st;
    dis[st]=0;
    while(l!=h)
    {
        u=que[h++];
        if(h==mn) h=0;
        for(int i=head[u]; i>=0; i=next[i])
        {
            v=reach[i];
            if(flow[i]&&dis[v]<0)
            {
                dis[v]=dis[u]+1;
                que[l++]=v;
                if(l==mn) l=0;
                if(v==sd) return true;
            }
        }
    }
    return false;
}

int dfs(int u, int exp)
{
    if(u==sd) return exp;
    for(int &i=work[u]; i>=0; i=next[i])
    {
        int v=reach[i], tp;
        if(flow[i]&&dis[v]==dis[u]+1&&(tp=dfs(v,min(flow[i],exp))>0))
        {
            flow[i]-=tp;
            flow[i^1]+=tp;
            return tp;
        }
    }
    return 0;
}

int Dinic()
{
    int max_flow=0, flow;
    while(bfs())
    {
        for(int i=0; i<node; i++) work[i]=head[i];
        while(flow=dfs(st,oo)) max_flow+=flow;
    }
    return max_flow;
}

int main()
{
    int m;
    while(cin >> m)
    {
        init(m*m+2,0,m*m+1);
        int sum=0, val;
        for(int i=1; i<=m; i++)
            for(int j=1; j<=m; j++)
            {
               scanf("%d",&val);
               sum+=val;
               if((i+j)&1)
               {
                   addedge(st,(i-1)*m+j,val,0);
                   if(i!=1) addedge((i-1)*m+j,(i-2)*m+j,oo,0);
                   if(i!=m) addedge((i-1)*m+j,i*m+j,oo,0);
                   if(j!=1) addedge((i-1)*m+j,(i-1)*m+j-1,oo,0);
                   if(j!=m) addedge((i-1)*m+j,(i-1)*m+j+1,oo,0);
               }
               else addedge((i-1)*m+j,sd,val,0);
            }
        printf("%d\n",sum-Dinic());
    }
    return 0;
}

 

 

 


posted @ 2013-03-25 17:10  Mr. Ant  阅读(367)  评论(0编辑  收藏  举报