bzoj 2132(最小割)

来源:互联网 发布:8点读报软件 编辑:程序博客网 时间:2024/04/29 08:46

2132: 圈地计划

Time Limit: 2 Sec  Memory Limit: 256 MB
Submit: 808  Solved: 362
[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


解题思路:和2172简直一模一样,不过相邻的两条边,要将商业边和工业边反过来,

可以黑白染色,然后建边,最后最大流就可以了。


#include <cstdio> 
#include <cstring> 
#include <iostream> 
#include <algorithm> 
#define M 10100 
#define P(x,y) ((x)*n-n+(y)) 
#define S 0 
#define T (m*n+1) 
#define INF 0x3f3f3f3f 
usingnamespace std; 
intm,n,ans; 
constint dx[]={1,-1,0,0}; 
constint dy[]={0,0,1,-1}; 
namespaceMax_Flow{ 
    structabcd{ 
        intto,f,next; 
    }table[1001001]; 
    inthead[M],tot=1; 
    intdpt[M]; 
    voidAdd(intx,inty,intz) 
    
        table[++tot].to=y; 
        table[tot].f=z; 
        table[tot].next=head[x]; 
        head[x]=tot; 
    
    voidLink(intx,inty,intz) 
    
        Add(x,y,z); 
        Add(y,x,z); 
    
    boolBFS() 
    
        staticint q[M]; 
        inti,r=0,h=0; 
        memset(dpt,-1,sizeofdpt); 
        dpt[S]=1;q[++r]=S; 
        while(r!=h) 
        
            intx=q[++h]; 
            for(i=head[x];i;i=table[i].next) 
                if(table[i].f&&!~dpt[table[i].to]) 
                
                    dpt[table[i].to]=dpt[x]+1; 
                    q[++r]=table[i].to; 
                    if(table[i].to==T) 
                        returntrue
                
        
        returnfalse
    
    intDinic(intx,intflow) 
    
        inti,left=flow; 
        if(x==T)returnflow; 
        for(i=head[x];i&&left;i=table[i].next) 
            if(table[i].f&&dpt[table[i].to]==dpt[x]+1) 
            
                inttemp=Dinic(table[i].to,min(left,table[i].f) ); 
                left-=temp; 
                table[i].f-=temp; 
                table[i^1].f+=temp; 
            
        if(left) dpt[x]=-1; 
        returnflow-left; 
    
intmain() 
    usingnamespace Max_Flow; 
    inti,j,k,x; 
    cin>>m>>n; 
    for(i=1;i<=m;i++) 
        for(j=1;j<=n;j++) 
        
            scanf("%d",&x); 
            ans+=x; 
            if(i+j&1) 
                Link(S,P(i,j),x); 
            else 
                Link(P(i,j),T,x); 
        
    for(i=1;i<=m;i++) 
        for(j=1;j<=n;j++) 
        
            scanf("%d",&x); 
            ans+=x; 
            if(~(i+j)&1) 
                Link(S,P(i,j),x); 
            else 
                Link(P(i,j),T,x); 
        
    for(i=1;i<=m;i++) 
        for(j=1;j<=n;j++) 
        
            scanf("%d",&x); 
            for(k=0;k<4;k++) 
            
                intxx=i+dx[k]; 
                intyy=j+dy[k]; 
                if(xx<=0||yy<=0||xx>m||yy>n) 
                    continue
                ans+=x; 
                Link(P(i,j),P(xx,yy),x); 
            
        
    while( BFS() ) 
        ans-=Dinic(S,INF); 
    cout<<ans<<endl; 
    return0; 

0 0
原创粉丝点击