zoukankan      html  css  js  c++  java
  • P2774 方格取数问题(最小割)

    P2774 方格取数问题

    一看题目便知是网络流,但由于无法建图....

    题目直说禁止那些条件,这导致我们直接建图做不到,既然如此,我们这是就要逆向思维,他禁止那些边,我们就连那些边.

    我们将棋盘染色,一个点向四周连边,我们的目标是使的这些边不起作用,我们将黑点与s联通,白点与t联通.

    之后我们就要考虑一个事情,只要一个黑点与白点由流,此时一定s到t有流.这样我们就能想到最小割...

    #include<bits/stdc++.h>
    #define ll long long
    using namespace std;
    const int N=110,INF=2e9;
    int sum,n,m,tot=1,s,t,dx[4]={-1,1,0,0},dy[4]={0,0,-1,1},d[N*N],current[N*N];
    int link[N*N],c[N][N];
    struct edge{int y,v,next;}a[N*N*8];
    inline int read()
    {
        int x=0,ff=1;
        char ch=getchar();
        while(!isdigit(ch)) {if(ch=='-') ff=-1;ch=getchar();}
        while(isdigit(ch)) {x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
        return x*ff;
    }
    inline void add(int x,int y,int v)
    {
        a[++tot].y=y;a[tot].v=v;a[tot].next=link[x];link[x]=tot;
        a[++tot].y=x;a[tot].v=0;a[tot].next=link[y];link[y]=tot;
    }
    inline bool bfs()
    {
        queue<int>q;q.push(s);
        memset(d,0,sizeof(d));
        memcpy(current,link,sizeof(current));
        d[s]=1;
        while(!q.empty())
        {
            int x=q.front();q.pop();
            for(int i=link[x];i;i=a[i].next)
            {
                int y=a[i].y;
                if(d[y]||!a[i].v) continue;
                d[y]=d[x]+1;
                q.push(y);
                if(y==t) return true;
            }
        }
        return false;
    }
    inline int dinic(int x,int flow)
    {
        if(x==t) return flow;
        int rest=flow,k;
        for(int i=current[x];i&&rest;i=a[i].next)
        {
            current[x]=i;
            int y=a[i].y;
            if(d[y]==d[x]+1&&a[i].v)
            {
                k=dinic(y,min(rest,a[i].v));
                if(!k) d[y]=0;
                a[i].v-=k;
                a[i^1].v+=k;
                rest-=k;
            }
        }
        return flow-rest;
    }
    int main()
    {
        freopen("1.in","r",stdin);
        n=read();m=read();
        for(int i=1;i<=n;++i)
            for(int j=1;j<=m;++j) c[i][j]=read(),sum+=c[i][j];
        s=0;t=n*m+1;
        for(int i=1;i<=n;++i)
            for(int j=1;j<=m;++j)
            {
                if((i+j)%2==0) 
                {
                    add(s,(i-1)*m+j,c[i][j]);    
                    for(int k=0;k<4;++k)
                    {
                        int x=i+dx[k],y=j+dy[k];
                        if(x>=1&&x<=n&&y>=1&&y<=m) add((i-1)*m+j,(x-1)*m+y,INF);
                    }
                }
                else add((i-1)*m+j,t,c[i][j]);    
            }    
        int maxflow=0,flow;
        while(bfs())
            while(flow=dinic(s,INF)) maxflow+=flow;
        printf("%d",sum-maxflow);
        return 0;    
    }
    View Code
  • 相关阅读:
    free和delete把指针怎么啦?
    动态内存会被自动释放吗?
    杜绝“野指针”
    有了malloc/free为什么还要new/delete ?
    Linux Shell Bash 带有特殊含义的退出码
    centos中更换jdk的版本
    shift移动变量
    shell script针对参数已经有配置好变量名称
    输入两个数后输出相乘的结果
    输入变量
  • 原文地址:https://www.cnblogs.com/gcfer/p/12544244.html
Copyright © 2011-2022 走看看