Jeanny
寂兮,寥兮,独立不改,周行而不殆

m*n 个方格,从方格中取数,使任意 2 个数所在方格没有公共边,且取出的数的总和最大。

∑所有的数-min(相邻的取)

min(相邻的取)为最小割

//最小割 
//longlong 写成int RE 
#include<bits/stdc++.h>
#define inf 0x3f3f3f3f 
using namespace std;
int m,n,cnt=1,hd[1005],vis[1005],d[1005]; 
long long a[1005][1005],sum;
struct Edge{
    int to,nxt,flw; 
}edge[100005<<1];
queue<int> q;
void add(int u,int v,int w)
{
    cnt++;
    edge[cnt].to=v;
    edge[cnt].nxt=hd[u];
    edge[cnt].flw=w;
    hd[u]=cnt;//又少了这一句。。。 
}
int tot=0;
int bfs(int s,int t)
{
    memset(vis,0,sizeof vis);
    while(!q.empty()) q.pop();
    vis[s]=1;
    d[s]=1;
    q.push(s);
    while(!q.empty())
    {
        int u=q.front();
        q.pop();
        for(int i=hd[u];i;i=edge[i].nxt)
        {
            int v=edge[i].to;
            if(edge[i].flw >0 && !vis[v])
            {
                
                d[v]=d[u]+1;
                vis[v]=1;
//                cout<<u<<","<<v<<","<<d[v]<<","<<edge[i].flw<<endl;
                q.push(v);
                if(v==t) 
                {
                    return 1;
                }
            }
        }
    }
    return 0;
}
int s=0,t;//t=m*n+1,所以这里是0

int dinic(int u,int res)
{
    if(u==t)return res;
    int sum=0;
    for(int i=hd[u];i;i=edge[i].nxt)
    {
        int v=edge[i].to ;
        if(edge[i].flw>0 && res>0 && d[v]==d[u]+1)//还有啥来着? 分层。。。 
        {
//            cout<<u<<","<<v<<","<<min(res,edge[i].flw)<<endl;
            int k=dinic(v,min(res,edge[i].flw));
//            if(!k) d[v]=0;
            edge[i].flw-=k;
            edge[i^1].flw+=k;
            sum+=k;
            res-=k;
            if(!res) break;
        }
    }
    return sum; 
} 
int main()
{
    scanf("%d%d",&m,&n);//注意m是行n是列 
    t=n*m+1;
    for(int i=1;i<=m;i++)
        for(int j=1;j<=n;j++)
        {
            scanf("%d",&a[i][j]);
            sum+=a[i][j];
        }
    for(int i=1;i<=m;i++)
        for(int j=1;j<=n;j++)
        {
            int p=(i-1)*n+j;
            if((i+j)%2==1) //这是右部点(2,4,6,8...),为了左部点连接到右部点的边权是无穷大 
            {
                add((i-1)*n+j,t,a[i][j]);
                add(t,(i-1)*n+j,0);
                continue;    //****continue右部点只和汇点连接,不和左部点连inf了 
            }
            add(s,(i-1)*n+j,a[i][j]);
            add((i-1)*n+j,s,0);    
            if(i-1>0)//和它的上一行连边 
            {
                add(p,(i-2)*n+j,inf);
                add((i-2)*n+j,p,0); 
            }
            if(j-1>0)
            {
                add(p,p-1,inf);
                add(p-1,p,0);
            }
            if(i+1<=m)
            {
                add(p,i*n+j,inf);
                add(i*n+j,p,0);
            }
            if(j+1<=n)
            {
                add(p,p+1,inf);
                add(p+1,p,0);
            }
        }        

//        for(int u=0;u<=t;u++)
//        {
//            for(int i=hd[u];i;i=edge[i].nxt)
//            {
//                cout<<u<<","<<edge[i].to<<","<<edge[i].flw<<endl;
//            }
//        }
    
//        for(int i=s;i<=t;i++)
//            cout<<i<<":"<<d[i]<<",";
        long long mxflw=0;
        while(bfs(s,t))
        {
//            for(int i=s;i<=t;i++)
//                cout<<i<<":"<<d[i]<<",";
            mxflw+=dinic(s,inf);
        }
        printf("%lld\n",sum-mxflw);
}

 

posted on 2018-07-12 10:59  Jeanny  阅读(163)  评论(0)    收藏  举报