BZOJ1475方格取数

1475: 方格取数
Time Limit: 5 Sec Memory Limit: 64 MB
Submit: 710 Solved: 361
Description
在一个n*n的方格里,每个格子里都有一个正整数。从中取出若干数,使得任意两个取出的数所在格子没有公共边,且取出的数的总和尽量大。
Input
第一行一个数n;(n<=30) 接下来n行每行n个数描述一个方阵
Output
仅一个数,即最大和
Sample Input
2
1 2
3 5
Sample Output
6
如果x+y为奇数,(x,y)->T,容量v[x,y]
如果x+y为偶数,S->(x,y),容量v[x,y]
并向四个方向的点连边,容量inf
答案为总收益减去最小割
附上本蒟蒻的代码:

#include<cstdio>
#include<iostream>
#include<cstring>
using namespace std;
#define inf 0x7fffffff
int n,xx[4]={0,0,1,-1},yy[4]={1,-1,0,0},map[31][31],mark[31][31],h[10001],dis[10001],q[10001],head,tail,cnt=1,ans=0,sum;
struct kx
{
    int to,next,v;
}edge[10001];

bool pd(int x,int y)
{
    if (x<1 || y<1 || x>n || y>n) return false;
    else return true;
}

int read()
{
    int w=0,c=1; char ch=getchar();
    while (ch<'0' || ch>'9')
      {
        if (ch=='-') c=-1;
        ch=getchar();
      }
    while (ch>='0' && ch<='9')
      w=w*10+ch-'0',ch=getchar();
    return w*c;
}

void add(int u,int v,int w)
{
    cnt++,edge[cnt].next=h[u],h[u]=cnt,edge[cnt].to=v,edge[cnt].v=w;
    cnt++,edge[cnt].next=h[v],h[v]=cnt,edge[cnt].to=u,edge[cnt].v=0;
}

bool bfs()
{
    int j,p;
    memset(dis,-1,sizeof(dis));
    q[0]=0;
    dis[0]=0;
    head=0;
    tail=1;
    while (head<tail)
      {
        head++;
        j=q[head];
        p=h[j];
        while (p)
          {
            if (dis[edge[p].to]<0 && edge[p].v>0)
              {
                  dis[edge[p].to]=dis[j]+1;
                  tail++;
                  q[tail]=edge[p].to;
              }
            p=edge[p].next;
          }
      }
    if (dis[n*n+1]>0)
      return true;
    else
      return false;
}

int dfs(int x,int f)
{
    int w,used=0,i=h[x];
    if (x==n*n+1)
      return f;
    while (i)
      {
        if (edge[i].v && dis[edge[i].to]==dis[x]+1)
          {
            w=f-used;
            w=dfs(edge[i].to,min(w,edge[i].v));
            edge[i].v-=w;
            edge[i^1].v+=w;
            used+=w;
            if (used==f)
              return f;
          }
        i=edge[i].next;
      }
    if (!used)
      dis[x]=-1;
    return used;
}

int main()
{
    int i,j,b=0,w,k;
    n=read();
    for (i=1;i<=n;i++)
      for (j=1;j<=n;j++)
        map[i][j]=read(),ans+=map[i][j];
    w=(n*n+1)/2;
    for (i=1;i<=n;i++)
      for (j=1;j<=n;j++)
        if ((i+j)%2==0)
          b++,mark[i][j]=b;
        else
          w++,mark[i][j]=w;
    for (i=1;i<=n;i++)
      for (j=1;j<=n;j++)
        if ((i+j)%2==0)
          {
            add(0,mark[i][j],map[i][j]);
            for (k=0;k<4;k++)
              if (pd(i+xx[k],j+yy[k]))
                add(mark[i][j],mark[i+xx[k]][j+yy[k]],inf);
          }
        else
          add(mark[i][j],n*n+1,map[i][j]);
    while (bfs())
      while (sum=dfs(0,inf))
        ans-=sum;
    printf("%d",ans);
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值