P2774 方格取数问题

题目描述

在一个有 m*n 个方格的棋盘中,每个方格中有一个正整数。现要从方格中取数,使任意 2 个数所在方格没有公共边,且取出的数的总和最大。试设计一个满足要求的取数算法。对于给定的方格棋盘,按照取数要求编程找出总和最大的数。

输入输出格式

输入格式:

第 1 行有 2 个正整数 m 和 n,分别表示棋盘的行数和列数。接下来的 m 行,每行有 n 个正整数,表示棋盘方格中的数。

输出格式:

程序运行结束时,将取数的最大总和输出

输入输出样例

输入样例#1: 复制
3 3
1 2 3
3 2 3
2 3 1 
输出样例#1: 复制
11

说明

该题求的是 最大独立集团权值和   因为所取的点没有两点是相邻的

所以把相邻点连起来!

由前面二分匹配知   最大独立集团=顶点数-最小覆盖点 加上权值也是一样的

所以最大独立集团权值和 ==总权值-最小覆盖点权值和 

所以求出最小覆盖点权值和即可   且=最小割=最大流

奇偶建图

源点-奇数  奇数和所有相邻的建图   偶数 -汇点

按照我自己的理解

先按照矛盾条件建图 (也就是 相邻的相连)

然后跑最大流  也就是最小割   

最小的消耗使得(该矛盾图无路可走 也就是没有任何一个矛盾成立 )  剩下的都是符合题意的流

sum-最小割即为答案!

离散化要*m   dubug了一个小时qwq

#include<bits/stdc++.h>
using namespace std;
//input by bxd
#define rep(i,a,b) for(int i=(a);i<=(b);i++)
#define repp(i,a,b) for(int i=(a);i>=(b);--i)
#define RI(n) scanf("%d",&(n))
#define RII(n,m) scanf("%d%d",&n,&m)
#define RIII(n,m,k) scanf("%d%d%d",&n,&m,&k)
#define RS(s) scanf("%s",s);
#define ll long long
#define pb push_back
#define REP(i,N)  for(int i=0;i<(N);i++)
#define CLR(A,v)  memset(A,v,sizeof A)
//////////////////////////////////
#define inf 0x3f3f3f3f
const int N=10000+5;
const int M=200000+5;
int head[M],pos,m,n;
struct Edge
{
    int to,nex=-1,v;
}edge[M];
void init()
{
    pos=-1;
    CLR(head,-1);
}
void add(int a,int b,int c)
{
    edge[++pos].nex=head[a];
    head[a]=pos;
    edge[pos].to=b;
    edge[pos].v=c;
    edge[++pos].nex=head[b];
    head[b]=pos;
    edge[pos].to=a;
    edge[pos].v=0;
}

int deth[N];
int bfs(int s,int t)
{
    CLR(deth,0);
    queue<int>q;
    deth[s]=1;
    q.push(s);
    while(!q.empty())
    {
        int u=q.front();q.pop();
        for(int i=head[u];i!=-1;i=edge[i].nex)
        {
            int v=edge[i].to;
            if(edge[i].v>0&&deth[v]==0)
            {
                deth[v]=deth[u]+1;
                q.push(v);
            }
        }
    }
    return deth[t];
}
int dfs(int s,int t,int dis)
{
    if(s==t)return dis;
    for(int i=head[s];i!=-1;i=edge[i].nex)
    {
        int v=edge[i].to;
        if(deth[v]==deth[s]+1&&edge[i].v!=0)
        {
            int di=dfs(v,t,min(dis,edge[i].v));
            if(di>0)
            {
                edge[i].v-=di;
                edge[i^1].v+=di;
                return di;
            }
        }
    }
    return 0;
}

int dinic(int s,int t)
{
    int ans=0;
    while(bfs(s,t))
        while(int di=dfs(s,t,inf))
        ans+=di;
    return ans;
}
int dx[]={0,0,1,-1};
int dy[]={1,-1,0,0};
int id(int x,int y)
{
    return (x-1)*m+y+2;
}
int main()
{

       RII(n,m);
       int s=1,t=2;
       init();
       ll sum=0;
       rep(i,1,n)
       rep(j,1,m)
       {
           int x;RI(x);
           sum+=x;

           if((i+j)&1)
            add(s,id(i,j),x);
           else add(id(i,j),t,x);

           if((i+j)&1)
           {
               rep(k,0,3)
               {
                   int x=i+dx[k];
                   int y=j+dy[k];
                   if(x>=1&&x<=n&&y>=1&&y<=m)
                    add(id(i,j),id(x,y),inf);
               }
           }
       }
    cout<<sum-dinic(s,t);

}
View Code
原文地址:https://www.cnblogs.com/bxd123/p/10828204.html