博客园 首页 私信博主 显示目录 隐藏目录 管理 动画

洛谷 P2774 方格取数问题 解题报告

主要说一下针对这种类型的题的思路:

  1. 首先算出最大得到的值,我们求最小割。
  2. 将网格图按照(行+列)的奇偶性分开,变成一个二分图
  3. 由奇点向偶点连边,走了一个不能走另一个的话,就连inf边(表示不可能割掉这条边)
  4. 具体细节根据题目分析

 

然后再来讲一下这道题:

同样非常的模板x.

  • 记录一个ans,表示权值和。
  • 我们对于每一个点,奇点就和s连边,偶点就和t连边,边容量=该点权值。
  • 然后对于每一个奇点,向它四周的点连inf边(注意判定边界),表示这条边不能割,即这两个点与s/t的连边必须割去一个,也就是不能共存。
  • 然后跑Dinic求出最小割,ans-maxflow就是答案。

代码如下:

#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <algorithm>
#include <queue>
#define ll long long
#define space putchar(' ')
#define endl putchar('\n')
#define debug puts("------------------------")
#define F(i,x,n) for(int i=x;i<=n;++i)
#define F_(i,x,n) for(int i=x;i>=n;--i)
using namespace std;
inline void read(int &a) {a=0;int c=getchar(),b=1; while(c>'9'||c<'0') {if(c=='-')b=-1;c=getchar();} while(c>='0'&&c<='9') a=(a<<3)+(a<<1)+c-48,c=getchar();a*=b; }
inline int  Rem() {int a=0,c=getchar(),b=1; while(c>'9'||c<'0') {if(c=='-')b=-1;c=getchar();} while(c>='0'&&c<='9') a=(a<<3)+(a<<1)+c-48,c=getchar();return a*=b; }
inline void write(int x) {if(x>9)write(x/10);putchar('0'+x%10);}
inline void W(int x) {if(x<0){putchar('-'),x=-x;}write(x);}
/**/
const int N=105*105,inf=0x3f3f3f3f;
const int fx[]={0,0,1,-1},fy[]={1,-1,0,0};
int n,m,s,t,head[N],cnt=1,dep[N],cur[N];
ll maxflow,ans;
bool vis[N];
struct edge
{
    int nxt,to,c;
}e[N*100];
/**/
namespace DINIC
{
    inline void add_one(int u,int v,int c)
    {
        e[++cnt]=(edge){head[u],v,c};
        head[u]=cnt;
    }
    inline void add(int u,int v,int c)
    {
        add_one(u,v,c);
        add_one(v,u,0);
    }
    inline bool bfs()
    {
        memset(dep,0x3f,sizeof(dep));
        memset(vis,0,sizeof(vis));
        memcpy(cur,head,sizeof(head));
        vis[s]=1,dep[s]=0;
        queue<int>q;
        q.push(s);
        while(!q.empty())
        {
            int u=q.front();q.pop();vis[u]=0;
            for(int i=head[u];i;i=e[i].nxt)
            {
                int v=e[i].to;
                if(dep[v]>dep[u]+1&&e[i].c)
                {
                    dep[v]=dep[u]+1;
                    if(!vis[v])
                    {
                        vis[v]=1;
                        q.push(v);
                    }
                }
            }
        }
        return dep[t]!=inf;
    }
    int dfs(int u,int flow)
    {
        if(u==t)
        {
            vis[t]=1;
            maxflow+=flow;
            return flow;
        }
        int used=0,minflow=0;
        for(int i=cur[u];i;i=e[i].nxt)
        {
            cur[u]=i;
            int v=e[i].to;
            if(dep[v]==dep[u]+1&&e[i].c)
            {
                if((minflow=dfs(v,min(flow-used,e[i].c)))!=0)
                {
                    used+=minflow;
                    e[i].c-=minflow;
                    e[i^1].c+=minflow;
                    if(used==flow) break;
                }
            }
        }
        return used;
    }
    ll Dinic()
    {
        while(bfs())
        {
            vis[t]=1;
            while(vis[t])
            {
                vis[t]=0;
                dfs(s,inf);
            }
        }
        return maxflow;
    }
}using namespace DINIC;
int get(int x,int y)
{
    return m*(x-1)+y;
}
int main()
{
    read(n);read(m);s=n*m+1,t=s+1;
    for(int i=1,x;i<=n;i++)
    {
        for(int j=1;j<=m;j++)
        {
            read(x);ans+=x;
            if((i+j)&1) add(s,get(i,j),x);
            else add(get(i,j),t,x);
        }
    }
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=m;j++)
        {
            if((i+j)&1)
            for(int k=0;k<4;k++)
            {
                int x=i+fx[k],y=j+fy[k];
                if(x<1||y<1||x>n||y>m) continue;
                add(get(i,j),get(x,y),inf);
            }        
        }
    }
    cout<<ans-Dinic();
}
code

 

posted @ 2019-03-13 20:41  楚泫  阅读(180)  评论(0编辑  收藏  举报