题目链接:  

m=ProblemSet&a=showProblem&problem_id=2163">点击打开链接

Description :

给你一个n*n的格子的棋盘,每一个格子里面有一个非负数。如今从中取出若干个数,使得随意的两个数所在的格子没有公共边,就是说所取的数所在的2个格子不能相邻。而且取出的数的和最大。




Input :

包含多个測试实例,每一个測试实例包含一个整数n 和n*n个非负数x(n<=20, 0 <= x <= 1000)。

Output :

对于每一个測试实例。输出可能取得的最大的和。




Sample Input :

3

258 83 905

874 941 662

733 415 890



Sample Output :

3727

解析:

一開始的方法(代码):

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#define MAXN 25
#define RST(N)memset(N, 0, sizeof(N))
using namespace std; int n, res, Max;
int Map[MAXN][MAXN], vis[MAXN][MAXN];
const int dx[] = {-1, 1, 1, -1};
const int dy[] = {1, 1, -1, -1}; int max(int x, int y) { return x>y ? x:y; } bool check(int x, int y)
{
return x>=1&&x<=n&&y>=1&&y<=n&&!vis[x][y];
} void solve(int px, int py)
{
int xx, yy;
vis[px][py] = 1;
//printf("%d(px), %d(py)\n", px, py);
for(int i=0; i<4; i++) {
xx = px+dx[i];
yy = py+dy[i];
if(check(xx, yy)) {
//printf("%d(xx), %d(yy) is usable\n", xx, yy);
solve(xx, yy);
}
//else printf("%d(xx), %d(yy) is XXXXXXX\n", xx, yy);
}
res += Map[px][py];
//printf("res = %d\n", res);
} int main()
{
while(~scanf("%d", &n)) {
Max = -1;
for(int i=1; i<=n; i++) {
for(int j=1; j<=n; j++) {
scanf("%d", &Map[i][j]);
}
}
if(n == 1) printf("%d\n", Map[1][1]);
else if(n == 2) {
printf("%d\n", max(Map[1][1]+Map[2][2], Map[1][2]+Map[2][1]));
}else {
for(int i=1; i<=n; i++) {
for(int j=1; j<=n; j++) {
res = 0;
RST(vis);
solve(i, j);
if(res > Max) Max = res;
}
}
printf("%d\n", Max);
}
}
return 0;
}

一開始想到的方法感觉非常对非常对。然后过了几天又一次做的时候突然想到一个过不去的情况,所以就想到了网络流;

一開始用的是深搜。思路是:

watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQva2VzaGFjb29raWU=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" alt="">

遍历二维数组中的每个点,然后递归遍历每个和当前点无重边的点。这样的方法能測试到大多数情况;但还是菜鸟思想。由于好久没怎么刷题了,思维有点跟不上了;这样的方法对于下面这样的情况就測试不正确了:

假设输入数据:

3

520   10    45

10     70    600

10     60    55

按上述方法的话会出现下面两种情况:

最后出现两种结果: 520+70+45+55+10 = 700     10+600+60+10=680

这两种答案都是错误的,由于正确的应该是:  520 + 600 + 60 = 1180

watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQva2VzaGFjb29raWU=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" alt="">

这个题因为数据范围较大,所以状态压缩过不去,须要用网络流,我反复一遍建图:

我们知道对于普通二分图来说,最大独立点集 + 最小点覆盖集 = 总点数,类似的,对于有权的二分图来说。有:

最大点权独立集 + 最小点权覆盖集 = 总点权和。

这个题非常明显是要求 最大点权独立集 。如今 总点权 已知,我们仅仅要求出来 最小点权覆盖集 就好了。我们能够这样建图,

1,对矩阵中的点进行黑白着色(相邻的点颜色不同),从源点向黑色的点连一条边,权值为该黑色点的权值。

2,从白色的点向汇点连一条边,权值为该白色点的权值,

3。然后。对于每一对相邻的黑白点,从黑点向白点连一条边。权值为无穷大。

最后求最小割(最大流)。即为最小点权覆盖集。

由于我们求出的最小割集一定是从那些相邻的黑白点之间的边(也就是不能用的边。由于相邻的数不能同一时候选)中选出来的,且是最小代价,也就是说从方格中拿掉的数之和尽量小,那么剩下的数之和一定是最大的。

代码例如以下:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>
#include <cstdlib>
#include <algorithm>
#define VM 2520
#define EM 500050
#define INF 0x3f3f3f3f
#define RST(N)memset(N, 0, sizeof(N))
using namespace std; struct Edge
{
int u, v, nxt;
int flow;
}edge[EM << 1]; int n, m, cnt, head[VM];
int src, des, dep[VM]; void addedge(int cu, int cv, int cf)
{
edge[cnt].u = cu, edge[cnt].v = cv, edge[cnt].flow = cf;
edge[cnt].nxt = head[cu], head[cu] = cnt++; edge[cnt].u = cv, edge[cnt].v = cu, edge[cnt].flow = 0;
edge[cnt].nxt = head[cv], head[cv] = cnt++;
} int dir[4][2]= {{-1, 0}, {1, 0}, {0, -1}, {0, 1}}; int legal(int i, int j, int k)
{
int x = i + dir[k][0];
int y = j + dir[k][1];
return x>=1 && x<=n && y>=1 && y<=m;
} int BFS() //又一次建图(按层数建图)
{
queue <int> q;
while(!q.empty()) q.pop();
memset(dep, -1, sizeof(dep));
dep[src] = 0;
q.push(src);
while(!q.empty()) {
int u = q.front();
q.pop();
for(int i=head[u]; i!=-1; i=edge[i].nxt) {
int v = edge[i].v;
if(edge[i].flow>0 && dep[v]==-1) { // 假设能够到达但还没有訪问
dep[v] = dep[u] + 1;
q.push(v);
}
}
}
return dep[des] != -1;
} /*
int DFS(int u,int minx) //查找路径上的最小的流量
{
if(u == des) return minx;
int tmp;
for(int i=head[u]; i!=-1; i=edge[i].nxt) {
int v = edge[i].v;
if(edge[i].flow>0 && dep[v]==dep[u]+1 && (tmp=DFS(v, min(minx, edge[i].flow)))) {
edge[i].flow -= tmp;
edge[i^1].flow += tmp;
return tmp;
}
}
return 0;
}
*/ int DFS(int u,int minx)
{
int ans = 0;
if(u == des) return minx;
for(int i=head[u]; i!=-1 && ans<minx; i=edge[i].nxt) {
int v = edge[i].v;
if(edge[i].flow>0 && dep[v]==dep[u]+1){
int tmp = min(edge[i].flow, minx-ans);
tmp = DFS(v,tmp);
ans += tmp;
edge[i].flow -= tmp;
edge[i^1].flow += tmp;
}
}
if(!ans) dep[u] = -2;
return ans;
} int Dinic()
{
int ans = 0, tmp;
while(BFS()) {
while(1) {
tmp = DFS(src, INF);
if(tmp == 0) break;
ans += tmp;
}
}
return ans;
} void Init()
{
m = n;
cnt = src = 0;
des = n * m + 1;
memset(head, -1, sizeof(head));
} int main(int argc, char **argv)
{
while(~scanf("%d", &n)) {
Init();
int x, sum = 0;
for(int i=1; i<=n; i++) {
for(int j=1; j<=m; j++) {
scanf("%d", &x);
sum += x;
if((i+j)%2 == 0) {
addedge(src, (i-1)*m+j, x);
for(int k=0; k<4; k++) {
if(legal(i, j, k)) addedge((i-1)*m+j, (i+dir[k][0]-1)*m+(j+dir[k][1]), INF);
}
}else {
addedge((i-1)*m+j, des, x);
for(int k=0; k<4; k++) {
if(legal(i, j, k)) addedge((i+dir[k][0]-1)*m+(j+dir[k][1]), (i-1)*m+j, INF);
}
}
}
}
int maxflow = Dinic();
printf("%d\n", sum-maxflow);
}
return 0;
}

HLG 2163 方格取数 (最大网络流)的更多相关文章

  1. P2774 方格取数问题 网络流重温

    P2774 方格取数问题 这个题目之前写过一次,现在重温还是感觉有点难,可能之前没有理解透彻. 这个题目要求取一定数量的数,并且这些数在方格里面不能相邻,问取完数之后和最大是多少. 这个很好的用了网络 ...

  2. P2774 方格取数问题 网络流

    题目: P2774 方格取数问题 题目背景 none! 题目描述 在一个有 m*n 个方格的棋盘中,每个方格中有一个正整数.现要从方格中取数,使任意 2 个数所在方格没有公共边,且取出的数的总和最大. ...

  3. CODEVS_1227 方格取数2 网络流 最小费用流 拆点

    原题链接:http://codevs.cn/problem/1227/ 题目描述 Description 给出一个n*n的矩阵,每一格有一个非负整数Aij,(Aij <= 1000)现在从(1, ...

  4. LibreOJ #6007. 「网络流 24 题」方格取数 最小割 最大点权独立集 最大流

    #6007. 「网络流 24 题」方格取数 内存限制:256 MiB时间限制:1000 ms标准输入输出 题目类型:传统评测方式:文本比较 上传者: 匿名 提交提交记录统计讨论测试数据   题目描述 ...

  5. Libre 6007 「网络流 24 题」方格取数 / Luogu 2774 方格取数问题 (网络流,最大流)

    Libre 6007 「网络流 24 题」方格取数 / Luogu 2774 方格取数问题 (网络流,最大流) Description 在一个有 m*n 个方格的棋盘中,每个方格中有一个正整数.现要从 ...

  6. HDU 1565 - 方格取数(1) - [状压DP][网络流 - 最大点权独立集和最小点权覆盖集]

    题目链接:https://cn.vjudge.net/problem/HDU-1565 Time Limit: 10000/5000 MS (Java/Others) Memory Limit: 32 ...

  7. AC日记——[网络流24题]方格取数问题 cogs 734

    734. [网络流24题] 方格取数问题 ★★☆   输入文件:grid.in   输出文件:grid.out   简单对比时间限制:1 s   内存限制:128 MB «问题描述: 在一个有m*n ...

  8. Cogs 734. [网络流24题] 方格取数问题(最大闭合子图)

    [网络流24题] 方格取数问题 ★★☆ 输入文件:grid.in 输出文件:grid.out 简单对比 时间限制:1 s 内存限制:128 MB «问题描述: 在一个有m*n 个方格的棋盘中,每个方格 ...

  9. 网络流(最大流) HDU 1565 方格取数(1) HDU 1569 方格取数(2)

      HDU 1565 方格取数(1) 给你一个n*n的格子的棋盘,每个格子里面有一个非负数.从中取出若干个数,使得任意的两个数所在的格子没有公共边,就是说所取的数所在的2个格子不能相邻,并且取出的数的 ...

随机推荐

  1. Cocos2d-x使用android拍照功能加载照片内存过大,通过另存照片尺寸大小解决

    使用2dx调用android拍照功能,拍照结束后在2dx界面显示拍照照片,如果不对照片做处理,会出现内存过大的问题,导致程序崩溃,如果仅仅另存拍照照片,则照片质量大小均下降,导致照片不够清晰,后来发现 ...

  2. 20款Notepad++插件下载和介绍

    转自:http://www.kuqin.com/developtool/20090628/59334.html Notepad++从3.4版本开始支持插件机制,让用户可选择的为本身已经优秀的Notep ...

  3. Xcode4.6 自制iOS可用的 Framework

    First of all:新建一个空白project. File->New->Project 然后新建两个文件 File->New->File  如图 然后选择targets ...

  4. Caffe —— Deep learning in Practice

    因工作交接须要. 要将caffe用法及总体结构描写叙述清楚. 鉴于也有同学问过我相关内容, 决定在本文中写个简单的tutorial, 方便大家參考. 本文简单的讲几个事情: Caffe能做什么? 为什 ...

  5. hdu 4812 D Tree(树的点分治)

    D Tree Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 102400/102400 K (Java/Others) Total ...

  6. POJ 2115 C Looooops(扩展欧几里得应用)

    题目地址:POJ 2115 水题. . 公式非常好推.最直接的公式就是a+n*c==b+m*2^k.然后能够变形为模线性方程的样子,就是 n*c+m*2^k==b-a.即求n*c==(b-a)mod( ...

  7. 解决Ajax.BeginForm还是刷新页面的问题

    在.net mvc中用Ajax.BeginForm来实现异步提交,在Ajax.BeginForm里面还是可以用submit按钮,一般来说 submit按钮是提交整个页面的数据.但是在Ajax.Begi ...

  8. 算法设计与分析——多边形游戏(DP)

    1.问题描述:   给定N个顶点的多边形,每个顶点标有一个整数,每条边上标有+(加)或是×(乘)号,并且N条边按照顺时针依次编号为1~N.下图给出了一个N=4个顶点的多边形. 游戏规则 :(1) 首先 ...

  9. Mongdb 访问

    http://114.55.75.xx/pics/201607040751367d21a38035bd4da7abd4473783f85f7a

  10. IE浏览器上传文件时本地路径变成”C:\fakepath\”的问题

    在使用<input id="file_upl" type="file" />控件上传文件时,有时会需要获取文件本地路径展示给客户,这时可以通过这样的 ...