bzoj 2132: 圈地计划

2132: 圈地计划

Time Limit: 2 Sec   Memory Limit: 256 MB
Submit: 918   Solved: 417
[ Submit][ Status][ Discuss]

Description

最近房地产商GDOI(Group of Dumbbells Or Idiots)从NOI(Nuts Old Idiots)手中得到了一块开发土地。据了解,这块土地是一块矩形的区域,可以纵横划分为N×M块小区域。GDOI要求将这些区域分为商业区和工业区来开发。根据不同的地形环境,每块小区域建造商业区和工业区能取得不同的经济价值。更具体点,对于第i行第j列的区域,建造商业区将得到Aij收益,建造工业区将得到Bij收益。另外不同的区域连在一起可以得到额外的收益,即如果区域(I,j)相邻(相邻是指两个格子有公共边)有K块(显然K不超过4)类型不同于(I,j)的区域,则这块区域能增加k×Cij收益。经过Tiger.S教授的勘察,收益矩阵A,B,C都已经知道了。你能帮GDOI求出一个收益最大的方案么?

Input

输入第一行为两个整数,分别为正整数N和M,分别表示区域的行数和列数;第2到N+1列,每行M个整数,表示商业区收益矩阵A;第N+2到2N+1列,每行M个整数,表示工业区收益矩阵B;第2N+2到3N+1行,每行M个整数,表示相邻额外收益矩阵C。第一行,两个整数,分别是n和m(1≤n,m≤100);

任何数字不超过1000”的限制

Output

输出只有一行,包含一个整数,为最大收益值。

Sample Input

3 3
1 2 3
4 5 6
7 8 9
9 8 7
6 5 4
3 2 1
1 1 1
1 3 1
1 1 1

Sample Output

81
【数据规模】
对于100%的数据有N,M≤100

HINT

 数据已加强,并重测--2015.5.15

在下面对拍,最大数据都不会错,交上去很快就WA了,不知道为什么,很奇怪。

#include<iostream>    
#include<cstdio>    
#include<cstring>    
#include<algorithm>    
#include<queue>    
#include<cmath>    
#define N 120    
#define M 1000003    
using namespace std;    
int n,m,tot=-1,sum;    
int next[M],point[M],remain[M],v[M];    
int a[N][N],b[N][N],c[N][N],p[N][N];    
int deep[M],cur[M];  
int x[10]={0,1,0,-1},y[10]={1,0,-1,0};  
const int inf=1e9;  
void add(int x,int y,int z)    
{    
  tot++; next[tot]=point[x]; point[x]=tot; v[tot]=y; remain[tot]=z;    
  tot++; next[tot]=point[y]; point[y]=tot; v[tot]=x; remain[tot]=0;     
}   
void addedge(int x,int y,int z)
{
  tot++; next[tot]=point[x]; point[x]=tot; v[tot]=y; remain[tot]=z;
  tot++; next[tot]=point[y]; point[y]=tot; v[tot]=x; remain[tot]=z;
} 
bool bfs(int s,int t)    
{    
  memset(deep,0x7f,sizeof(deep));    
  for (int i=s;i<=t;i++) cur[i]=point[i];    
  deep[s]=0;     
  queue<int> p; p.push(s);    
  while(!p.empty())    
  {    
   int now=p.front(); p.pop();    
   for (int i=point[now];i!=-1;i=next[i])    
   if (deep[v[i]]>inf&&remain[i])    
    deep[v[i]]=deep[now]+1,p.push(v[i]);    
  }    
  if (deep[t]>inf) return false;    
  return true;    
}    
int dfs(int now,int t,int limit)  
{  
  if (now==t||!limit) return limit;  
  int flow=0,f;  
  for(int i=cur[now];i!=-1;i=next[i])  
  {  
    cur[now]=i;  
    if (deep[v[i]]==deep[now]+1&&(f=dfs(v[i],t,min(limit,remain[i]))))  
    {  
      flow+=f;  
      limit-=f;
      remain[i]-=f;  
      remain[i^1]+=f;  
      if (!limit) break;  
      }  
   }   
  return flow;  
}  
int dinic(int s,int t)    
{    
  int ans=0;    
  while (bfs(s,t))    
   ans+=dfs(s,t,inf);    
  return ans;    
}  
int main()    
{   
 freopen("a.in","r",stdin);
 freopen("my.out","w",stdout); 
 memset(point,-1,sizeof(point));
 memset(next,-1,sizeof(next));
 sum=0;
 scanf("%d%d",&n,&m);    
 for (int i=1;i<=n;i++)    
  for (int j=1;j<=m;j++) scanf("%d",&a[i][j]),sum+=a[i][j];   
 for (int i=1;i<=n;i++)    
  for (int j=1;j<=m;j++) scanf("%d",&b[i][j]),sum+=b[i][j];    
 for (int i=1;i<=n;i++)    
  for (int j=1;j<=m;j++) 
  {
   scanf("%d",&c[i][j]);
   if (i==1&&j==1||i==1&&j==m||i==n&&j==1||i==n&&j==m)
    sum+=c[i][j]*2;
   else
    if (i==1||j==1||i==n||j==m)   sum+=c[i][j]*3;
    else sum+=c[i][j]*4; 
  }
 for (int i=1;i<=n;i++)//黑白染色 
  for (int j=1;j<=m;j++)
  {
   if (i%2==1&&j%2==1)  p[i][j]=1;
   if (i%2==0&&j%2==0)  p[i][j]=1;
  }
 /*for (int i=1;i<=n;i++)
  {
    for (int j=1;j<=m;j++)
     cout<<p[i][j]<<" ";
    cout<<endl;
  }*/
 int num=n*m;    
 for (int i=1;i<=n;i++)    
  for (int j=1;j<=m;j++)   
   if (p[i][j])  add(0,(i-1)*m+j,a[i][j]),add((i-1)*m+j,num+1,b[i][j]);
   else add(0,(i-1)*m+j,b[i][j]),add((i-1)*m+j,num+1,a[i][j]);
 for (int i=1;i<=n;i++)    
  for (int j=1;j<=m;j++)  
   if (p[i][j])  
   {    
    int x=(i-1)*m+j;    
    if (i-1>0)  
	 addedge(x,(i-2)*m+j,c[i][j]+c[i-1][j]);   
    if (i+1<=n)  
	 addedge(x,i*m+j,c[i][j]+c[i+1][j]);    
    if (j-1>0)  
	 addedge(x,x-1,c[i][j]+c[i][j-1]);    
    if (j+1<=m)  
	 addedge(x,x+1,c[i][j]+c[i][j+1]);   
   }    
  int t=dinic(0,num+1);  
 // cout<<t<<endl; 
  //cout<<sum<<endl; 
  printf("%d\n",sum-t);
}    


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值