方格取数3

 方格取数 3

时间限制: 2 s

空间限制: 256000 KB

题目描述 Description

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

输入描述 Input Description

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

输出描述 Output Description

将取数的最大总和输出

样例输入 Sample Input

3 3
1 2 3
3 2 3
2 3 1

样例输出 Sample Output

11

数据范围及提示 Data Size & Hint

n,m<=30


最小割。由于题目要求不能选择相邻的两个数,我们可以考虑给棋盘染色,白格子只与黑格子相邻,反之亦然。源点都和某一种颜色的格子相连,汇点和另一种颜色的格子相连,权值为格子里的数。相邻两个格子之间建一条流量为无穷大的边,这样就保证最小割只会选择去除与源点或汇点相邻的边,而去除这条边就意味着不选这个格子里的数。最后当最小割选择完成后,源点和汇点没有路径相连,这就意味着没有相邻的格子被同时保留。(因为源点和汇点连接必须要经过相邻格子之间的边,而现在源点和汇点不相连,就意味着一旦某一个格子被选择,它周围的格子都不能再被选择了)。

#include<bits/stdc++.h>
#define N 1000
using namespace std;

long long tot=0;
typedef struct{long long v,flow;}ss;
vector<long long>edges[N];
ss edg[N*N];
long long dis[N];
long long S,T;
long long current[N];

void addedge(long long u,long long v,long long flow)
{
    edg[tot]=(ss){v,flow};
    edges[u].push_back(tot++);
    edg[tot]=(ss){u,0};
    edges[v].push_back(tot++);
}

bool bfs()
{
    queue<long long>q;
    q.push(S);
    for(long long i=0;i<N;i++)dis[i]=LLONG_MAX/2;
    dis[S]=1;

    while(!q.empty())
    {
        int now=q.front();
        q.pop();
        long long Size=edges[now].size();

        for(long long i=0;i<Size;i++)
        {
            ss &e=edg[edges[now][i]];

            if(e.flow>0&&dis[e.v]==LLONG_MAX/2)
            {
                dis[e.v]=dis[now]+1;
                q.push(e.v);
            }
        }
    }

    if(dis[T]==LLONG_MAX/2)return 0;
    return 1;
}

long long dfs(long long x,long long flow)
{
    if(x==T)return flow;

    long long Size=edges[x].size();
    for(long long i=current[x];i<Size;i++)
    {
        current[x]=i;
        ss &e=edg[edges[x][i]];
        if(dis[x]+1==dis[e.v]&&e.flow>0)
        {
            long long Flow=dfs(e.v,min(flow,(long long)e.flow));
            if(Flow!=0)
            {
                e.flow-=Flow;
                edg[edges[x][i]^1].flow+=Flow;
                return Flow;
            }
        }

    }
    return 0;

}
long long dinic()
{
    long long ans=0;
    while(bfs())
    {
        memset(current,0,sizeof(current));
        long long flow;
        while(flow=dfs(S,LLONG_MAX))ans+=flow;
    }
    return ans;
}

int main()
{
    int m,n,t=0;
    int Map[35][35];
    int num[35][35];

    long long ans=0;

    scanf("%d %d",&m,&n);
    for(int i=1;i<=m;i++)
    for(int j=1;j<=n;j++)
    {
        scanf("%d",&Map[i][j]);
        num[i][j]=t++;
        ans+=Map[i][j];

    }

    S=t++;
    T=t++;

    for(int i=1;i<=m;i++)
    {
        for(int j=(i+1)%2+1;j<=n;j+=2)
        {
            addedge(S,num[i][j],Map[i][j]);

            if(i-1>=1)addedge(num[i][j],num[i-1][j],LLONG_MAX/2);
            if(i+1<=m)addedge(num[i][j],num[i+1][j],LLONG_MAX/2);
            if(j-1>=1)addedge(num[i][j],num[i][j-1],LLONG_MAX/2);
            if(j+1<=n)addedge(num[i][j],num[i][j+1],LLONG_MAX/2);

        }

    }

    for(int i=1;i<=m;i++)
    {
        for(int j=i%2+1;j<=n;j+=2)
        {
            addedge(num[i][j],T,Map[i][j]);
        }
    }

    printf("%lld",ans-dinic());
    return 0;
}

原文地址:https://www.cnblogs.com/tian-luo/p/9501571.html

时间: 2024-11-09 09:45:38

方格取数3的相关文章

hdu 1565 方格取数(2)(网络流之最大点权独立集)

题目链接:hdu 1565 方格取数(2) 题意: 有一个n*m的方格,每个方格有一个数,现在让你选一些数.使得和最大. 选的数不能有相邻的. 题解: 我们知道对于普通二分图来说,最大独立点集 + 最小点覆盖集 = 总点数,类似的,对于有权的二分图来说,有: 最大点权独立集 + 最小点权覆盖集 = 总点权和, 这个题很明显是要求 最大点权独立集 ,现在 总点权 已知,我们只要求出来 最小点权覆盖集 就好了,我们可以这样建图, 1,对矩阵中的点进行黑白着色(相邻的点颜色不同),从源点向黑色的点连一

P1004 方格取数

P1004 方格取数 题目描述 设有N*N的方格图(N<=9),我们将其中的某些方格中填入正整数,而其他的方格中则放 人数字0.如下图所示(见样例): A 0 0 0 0 0 0 0 0 0 0 13 0 0 6 0 0 0 0 0 0 7 0 0 0 0 0 0 14 0 0 0 0 0 21 0 0 0 4 0 0 0 0 15 0 0 0 0 0 0 14 0 0 0 0 0 0 0 0 0 0 0 0 0 0 . B 某人从图的左上角的A点出发,可以向下行走,也可以向右走,直到到达右下角

hdoj 1569 方格取数(2) 【最小割】 【最大点权独立集】

方格取数(2) Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 5589    Accepted Submission(s): 1741 Problem Description 给你一个m*n的格子的棋盘,每个格子里面有一个非负数. 从中取出若干个数,使得任意的两个数所在的格子没有公共边,就是说所取数所在的2个格子不能相邻,并且取出的

1475: 方格取数

1475: 方格取数 Time Limit: 5 Sec  Memory Limit: 64 MBSubmit: 578  Solved: 309[Submit][Status][Discuss] Description 在一个n*n的方格里,每个格子里都有一个正整数.从中取出若干数,使得任意两个取出的数所在格子没有公共边,且取出的数的总和尽量大. Input 第一行一个数n:(n<=30) 接下来n行每行n个数描述一个方阵 Output 仅一个数,即最大和 Sample Input 2 1 2

hdu 1569 方格取数(2) 网络流 最大点权独立集

方格取数(2) Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 5146    Accepted Submission(s): 1610 Problem Description 给你一个m*n的格子的棋盘,每个格子里面有一个非负数. 从中取出若干个数,使得任意的两个数所在的格子没有公共边,就是说所取数所在的2个格子不能相邻,并且取出的

HDU 1565 方格取数(1) (状态压缩 DP)

方格取数(1) Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 5779    Accepted Submission(s): 2194 Problem Description 给你一个n*n的格子的棋盘,每个格子里面有一个非负数. 从中取出若干个数,使得任意的两个数所在的格子没有公共边,就是说所取的数所在的2个格子不能相邻,并且取出

HDU 1565 方格取数(1)(状压dp)

感觉这道题目的数据比较水啊,程序的时间复杂度为1711^2*20竟然也可以过掉....其他的就是状压了啊,注意需要滚动一下啊.... 方格取数(1) Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 5701    Accepted Submission(s): 2159 Problem Description 给你一个n*n的格子的棋

hdu 3657 最小割的活用 / 奇偶方格取数类经典题 /最小割

题意:方格取数,如果取了相邻的数,那么要付出一定代价.(代价为2*(X&Y))(开始用费用流,敲升级版3820,跪...) 建图:  对于相邻问题,经典方法:奇偶建立二分图.对于相邻两点连边2*(X&Y),源->X连边,Y->汇连边,权值w为点权. ans=总点权-最小割:如果割边是源->X,表示x不要选(是割边,必然价值在路径上最小),若割边是Y-汇点,同理:若割边是X->Y,则表示选Y点且选X点, 割为w( 2*(X&Y) ). 自己的确还没有理解其本质

hdu 4859 最大点权独立集的变形(方格取数的变形)

/*刚开始不会写,最大点权独立集神马都不知道,在潘神的指导下终于做出来,灰常感谢ps: 和方格取数差不多奇偶建图,对于D必割点权为0,对于.必然不割点权为inf.然后和方格取数差不多的建图 .--.||E权值为2,,.||E--D权值为0. 最大点权独立集=sum-最小点权覆盖. */ #include<stdio.h> #include<string.h> #include<queue> using namespace std; #define inf 0x3ffff

【网络流】hdu 1569 方格取数(2)

/* 和1565一样: 总点数的权 - 最小覆盖点集 = 最大独立集 -------------------------------------- void add(int u, int v, int f)加边 { e[ct].u = u; e[ct].v = v; e[ct].f = f; next[ct] = first[u]; first[u] = ct++; e[ct].u = v; e[ct].v = u; e[ct].f = 0; next[ct] = first[v]; first