Hrbust oj 2163 棋盘取数(二分图+最大流)

棋盘取数

Time Limit: 1000 MS Memory Limit: 32768 K

Total Submit: 66(22 users) Total Accepted: 18(11 users) Rating: Special Judge: No

Description

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

Input

包括多个测试实例,每个测试实例包括一个整数n 和n*n个非负数x(n<=20, 0 <= x <= 1000)。

Output

对于每个测试实例,输出可能取得的最大的和。

Sample Input

3

258 83 905

874 941 662

733 415 890

Sample Output

3727
题解:这是个二分图,求的是最大点权独立集。最大点权独立集=总权值-最小点权覆盖。设下标和为偶数的点为X,下表和为奇数的点为Y。则ss连x,流量为mp[x],y连tt,流量为mp[y].x连周围4个点,流量为INF。
代码:

#include<iostream>
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<vector>
#include<queue>
#include<stack>
#include<set>
#include<algorithm>
#include<map>
#include<time.h>
#include<math.h>
//#define pb push_back
//#define mp make_pair
#define INF 0x3f3f3f3f
using namespace std;
typedef long long int ll;
typedef pair<int,int>pp;
const int N=1e3+100;
const int mod=1e9+7;
int read()
{
    int x=0;
    char ch = getchar();
    while('0'>ch||ch>'9')ch=getchar();
    while('0'<=ch&&ch<='9')
    {
        x=(x<<3)+(x<<1)+ch-'0';
        ch=getchar();
    }
    return x;
}
/***********************************************************/
int fx[4]= {0,0,1,-1};
int fy[4]= {1,-1,0,0};
int t,n,m,u,v,c,ss,tt;
int cnt,sum;
struct node
{
    int to,w,next;
} edge[N<<2];
int dep[N];
int vis[N];
int head[N<<2];
int mp[50][50];
void add(int f,int to,int w)
{
    edge[cnt].to=to;
    edge[cnt].w=w;
    edge[cnt].next=head[f];
    head[f]=cnt++;
}
int makedep()
{
    memset(dep,0,sizeof(dep));
    queue<int>s;
    s.push(ss);
    dep[ss]=1;
    while(!s.empty())
    {
        int u=s.front();
        if(u==tt) return 1;
        s.pop();
        for(int i=head[u]; i!=-1; i=edge[i].next)
        {
            int v=edge[i].to;
            int w=edge[i].w;
            if(w&&dep[v]==0)
            {
                dep[v]=dep[u]+1;
                s.push(v);
            }
        }
    }
    return 0;
}
int dfs(int u,int maxflow,int tt)
{
    if(u==tt) return maxflow;
    int ret=0;
    for(int i=head[u]; i!=-1; i=edge[i].next)
    {
        int v=edge[i].to;
        int w=edge[i].w;
        if(w&&dep[v]==dep[u]+1)
        {
            int f=dfs(v,min(maxflow-ret,w),tt);
            edge[i].w-=f;
            edge[i^1].w+=f;
            ret+=f;
            if(ret==maxflow) return ret;
        }
    }
    return ret;
}
void Dinic()
{
    int ans=0;
    while(makedep()==1)
    {
        ans+=dfs(ss,INF,tt);
    }
    printf("%d\n",sum-ans);
}
void solve()
{
    for(int i=1; i<=n; i++)
    {
        for(int j=1; j<=n; j++)
        {
            if((j+i)%2==0)
            {
                add(ss,(i-1)*n+j,mp[i][j]);
                add((i-1)*n+j,ss,0);
            }
            else
            {
                add((i-1)*n+j,tt,mp[i][j]);
                add(tt,(i-1)*n+j,0);
            }
        }
    }
    for(int i=1; i<=n; i++)
    {
        for(int j=1; j<=n; j++)
        {
            if((i+j)%2==1) continue;
            else
            {
                for(int k=0; k<4; k++)
                {
                    int x=i+fx[k];
                    int y=j+fy[k];
                    if(x>=1&&x<=n&&y>=1&&y<=n)
                    {
                        add((i-1)*n+j,(x-1)*n+y,INF);
                        add((x-1)*n+y,(i-1)*n+j,0);
                    }
                }
            }
        }
    }
}
int main()
{
    while(~scanf("%d",&n))
    {
        cnt=0;
        memset(head,-1,sizeof(head));
        ss=n*n+1;
        tt=ss+1;
        sum=0;
        for(int i=1; i<=n; i++)
        {
            for(int j=1; j<=n; j++)
            {
                scanf("%d",&mp[i][j]);
                sum+=mp[i][j];
            }
        }
        solve();
        Dinic();
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值