HDU-3657-Game(同 方格取数 最小割)

题目
onmylove n×m网格上发明了一种游戏。每个网格上都有一个正整数。现在你可以从格子里取出数字,使你的最终得分尽可能高。获得分数的方法是

以下几点:
●在一开始,比分是0;
●如果你把一个数等于x,分数增加x;
●后如果出现两个相邻空网格数量,那么分数应该下降了2(x&y). 这里x和y是过去存在于这两个网格上的值。请注意,“相邻网格”是指这两个网格之间存在且仅存在一个公共边界。
由于onmylove认为这个问题太简单了,他又增加了一条规则:
●在你开始游戏之前,你有一些立场和这些位置上的数字必须带走。
你能帮onmylove计算一下吗:onmylove在游戏中最高得分是多少?

输入

多个输入病例。对于每一种情况,一行有三个整数n m k。
n和m描述网格的大小n×m。k表示有k个位置你必须取它们的数字。然后n行后,每个包含m数字,代表n×m网格上的数字。然后是k行。每一行包含两个整数,表示一个位置的行和列
你必须记下这个位置的数字。而且,行和列是从1开始计数的。

限制:1≤n m≤50 0 k≤≤n×m,每个准备的整数不超过1000人。

输出

对于每个测试用例,在一行中输出最高分。

Sample Input

2 2 1
2 2
2 2
1 1
2 2 1
2 7
4 1
1 1

Sample Output

4
9

最小割…奇偶建图
有些点是必须选的 这些点为偶格子则向s连INF的边 奇格子向t连INF的边
覆盖原来的边 导致原来的边不会被割,割了也没用 INF在这儿撑着呢 就代表这个点必选

#include <queue>
#include <cstring>
#include <cstdio>
#define  m(a,b) memset(a,b,sizeof a)
using namespace std;
typedef long long ll;
const int N=2500+5;
const int INF=0x3f3f3f3f;
struct Edge{int to,len,nex;}edge[N*8];
int head[N],d[N],a[N][N];
int tot,s,t,n,m;
void add(int from,int to,int len)
{
    edge[++tot]=(Edge){to,len,head[from]};head[from]=tot;
    edge[++tot]=(Edge){from,0,head[to]};head[to]=tot;
}
queue<int>q;
bool bfs()
{
    while(!q.empty())
        q.pop();
    m(d,0);
    q.push(s);
    d[s]=1;
    while(!q.empty())
    {
        int x=q.front();
        q.pop();
        for(int i=head[x];i;i=edge[i].nex)
        {
            int y=edge[i].to,l=edge[i].len;
            if(!d[y]&&l)
            {
                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 res=flow,k;
    for(int i=head[x];i&&res;i=edge[i].nex)
    {
        int y=edge[i].to,l=edge[i].len;
        if(l&&d[y]==d[x]+1)
        {
            k=dinic(y,min(res,l));
            if(!k)
            {
                d[y]=0;
                continue;
            }
            edge[i].len-=k;
            edge[i^1].len+=k;
            res-=k;
        }
    }
    return flow-res;
}
int main()
{
    int n,m,k;
    while(~scanf("%d%d%d",&n,&m,&k))
    {
        m(head,0);
        tot=1;
        s=0,t=n*m+1;
        ll sum=0;
        for(int i=1;i<=n;i++)
            for(int j=1;j<=m;j++)
                scanf("%d",&a[i][j]),sum+=a[i][j];
        while(k--)
        {
            int i,j;
            scanf("%d%d",&i,&j);
            int pos=(i-1)*m+j;
            if((i+j)&1)
                add(pos,t,INF);
            else
                add(s,pos,INF);
        }
        for(int i=1;i<=n;i++)
        {
            if(!(i&1))
                add((i-1)*m+1,t,a[i][1]);
            for(int j=(i&1)?1:2;j<=m;j+=2)
            {
                int pos=(i-1)*m+j;
                add(s,pos,a[i][j]);
                if(j<m)
                    add(pos+1,t,a[i][j+1]);
                if(i>1)
                    add(pos,pos-m,2*(a[i][j]&a[i-1][j]));
                if(i<n)
                    add(pos,pos+m,2*(a[i][j]&a[i+1][j]));
                if(j>1)
                    add(pos,pos-1,2*(a[i][j]&a[i][j-1]));
                if(j<m)
                    add(pos,pos+1,2*(a[i][j]&a[i][j+1]));
            }
        }
        ll maxflow=0;
        while(bfs())
            maxflow+=dinic(s,INF);
        printf("%lld\n",sum-maxflow);
    }
}

猜你喜欢

转载自blog.csdn.net/qq_42576687/article/details/87531899