码迷,mamicode.com
首页 > 其他好文 > 详细

方格取数问题(网络流)

时间:2020-03-04 09:20:31      阅读:63      评论:0      收藏:0      [点我收藏+]

标签:scan   problem   ==   cstring   价值   font   get   printf   网络流   

方格取数问题(luogu)

Solution

可以利用网络流对“斥”的求解

先假设所有点都选,不选某些点可以使选择的方案合法,求出这些不选的点的价值总和的最小值

最小值联想到最小割

根据(横坐标+纵坐标)的奇偶性将图分成两部分

在不能同时选的点间连边(方向偶-奇),由于“割”时不能割掉点之间不能同时选的关系,所以它的流量应为正无穷

再从起点向偶部的每个点连一条流量为这个点的价值的边,从奇部的每个点向终点连一条流量为这个点的价值的边,

表示不选它失去的价值

跑最大流(即最小割)

Code

 

#include <cstdio>
#include <cstdlib>
#include <queue>
#include <algorithm>
#include <cstring>
using namespace std;
const int N=1e4+10,M=1e5;
int head[N],nxt[M],ver[M],edge[M],tot=1;
int s,t,n,m,d[N],x,maxflow,flow,sum,inf=1<<30;
int id(int x,int y)
{
    return (x-1)*m+y;
}
void add(int u,int v,int w)
{
    ver[++tot]=v,nxt[tot]=head[u],edge[tot]=w,head[u]=tot;
    ver[++tot]=u,nxt[tot]=head[v],edge[tot]=0,head[v]=tot;
}
int bfs()
{
    queue <int> q;
    memset(d,0,sizeof(d));
    d[s]=1,q.push(s);
    while(!q.empty())
    {
        int x=q.front();
        q.pop();
        for(int i=head[x],y;i;i=nxt[i])
            if(edge[i]>0 && !d[y=ver[i]])
            {
                d[y]=d[x]+1;
                q.push(y);
                if(y==t) return 1;
            }
    }
    return 0;
}
int dinic(int x,int flow)
{
    if(x==t) return flow;
    int rest=flow;
    for(int i=head[x],y;i && rest;i=nxt[i])
        if(edge[i]>0 && d[y=ver[i]]==d[x]+1)
        {
            int k=dinic(y,min(edge[i],rest));
            if(!k) d[y]=0;
            edge[i]-=k,edge[i^1]+=k;
            rest-=k;
        }
    return flow-rest;
}
int main()
{
    scanf("%d%d",&n,&m);
    s=0,t=n*m+1;
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
        {
            scanf("%d",&x);
            sum+=x;
            if((i+j)%2) 
            {
                add(id(i,j),t,x);
                continue;
            }
            add(s,id(i,j),x);
            if(i>1) add(id(i,j),id(i-1,j),inf);
            if(i<n) add(id(i,j),id(i+1,j),inf);
            if(j>1) add(id(i,j),id(i,j-1),inf);
            if(j<m) add(id(i,j),id(i,j+1),inf);
        }
    while(bfs()) while(flow=dinic(s,1<<30)) maxflow+=flow;
    printf("%d\n",sum-maxflow);
    return 0;
}

 

 

 

方格取数问题(网络流)

标签:scan   problem   ==   cstring   价值   font   get   printf   网络流   

原文地址:https://www.cnblogs.com/hsez-cyx/p/12407490.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!