hdu acm 1565 方格取数(1)

方格取数(1)

Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 7386    Accepted Submission(s): 2806


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

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

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

Sample Input
  
  
3 75 15 21 75 15 28 34 70 5
 

Sample Output
  
  
188
 解题关键:黑白染色。(横纵坐标相加分成奇,偶两部分),构造超级源点,汇点。原点到奇数点的权值为该点上的值,奇数点到相邻点的权值为INF,偶数点到汇点的权值为该点的值。求最小割。
最小割=最大流。
ans=总数的和-最小割。
#include <iostream>
#include<string.h>
using namespace std;
#include<queue>
#define INF 0x7fffffff
#define MS(a,b) memset(a,b,sizeof(a))
int mat[505][505],n,s,t,dis[300000],f,head[500005];
#define MAXN 3000
#include<algorithm>
struct node
{
    int to,next,w;
}edge[500005];
void add(int u,int v,int w)
{
    edge[f].to=v;
    edge[f].next=head[u];
    edge[f].w=w;
    head[u]=f++;
    edge[f].to=u;
    edge[f].w=0;
    edge[f].next=head[v];
    head[v]=f++;
}
int bfs()
{
  int i,x,v;
  MS(dis,-1);
  dis[s]=0;
  queue<int>q;
  q.push(s);
  while(!q.empty())
  {
    x=q.front();
    q.pop();
    for(i=head[x];i!=-1;i=edge[i].next)
    {  v=edge[i].to;
      if(edge[i].w&&dis[v]==-1)
      {
          dis[v]=dis[x]+1;
          if(v==t)return 1;
          q.push(v);
      }
    }
  }
  return 0;
}
int dfs(int s,int cur_flow)
{
    int i,v,tmp,dt=cur_flow;//dt为当前剩余流量。
    if(s==t)return cur_flow;
    for(i=head[s];i!=-1;i=edge[i].next)
    {
       v=edge[i].to;
       if(edge[i].w&&dis[s]==dis[v]-1)
       {
         int flow=dfs(v,min(dt,edge[i].w));//一条增广路,能够增广的流量,只能是路上最小流量边的流量
               edge[i].w-=flow;//减少前向弧流量
               edge[i^1].w+=flow;//增加后向弧流量
               dt-=flow;//找到一条路,存起来
       }
    }
    return cur_flow-dt;//一共增广的流量
}
int dinic()
{
  int ans=0;
  while(bfs())
    ans+=dfs(s,INF);
  return ans;
}
int main()
{
   int i,j,sum,k,i1,j1;
   while(cin>>n)
   {
       t=n*n+n+1;
       f=sum=0;
       s=1;
   for(i=1;i<=n;i++)
     for(j=1;j<=n;j++)
    {
      cin>>mat[i][j];
      sum=sum+mat[i][j];
    }
     MS(head,-1);
    for(i=1;i<=n;i++)
      for(j=1;j<=n;j++)
    {
        if((i+j)%2==1)
        {
         add(1,i*n+j,mat[i][j]);
         if(i+1<=n)
             add(i*n+j,(i+1)*n+j,INF);
         if(i-1>=1)
             add(i*n+j,(i-1)*n+j,INF);
         if(j+1<=n)
             add(i*n+j,i*n+j+1,INF);
         if(j-1>=1)
             add(i*n+j,i*n+j-1,INF);
         }
          else
           add(i*n+j,t,mat[i][j]);
    }
    cout<<sum-dinic()<<endl;
    }
    return 0;
}




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值