【网络流】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;
    }

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

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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值