题目链接:https://vjudge.net/problem/HDU-1565

方格取数(1)

Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 9929    Accepted Submission(s): 3743

Problem Description
给你一个n*n的格子的棋盘,每个格子里面有一个非负数。
从中取出若干个数,使得任意的两个数所在的格子没有公共边,就是说所取的数所在的2个格子不能相邻,并且取出的数的和最大。
 
Input
包括多个测试实例,每个测试实例包括一个整数n 和n*n个非负数(n<=20)
 
Output
对于每个测试实例,输出可能取得的最大的和
 
Sample Input
3
75 15 21
75 15 28
34 70 5
 
Sample Output
188
 
Author
ailyanlu
 
Source
 

逐行递推:

 #include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <string>
#include <vector>
#include <map>
#include <set>
#include <queue>
#include <stack>
#include <sstream>
#include <algorithm>
using namespace std;
#define eps 0.0000001
typedef long long LL;
const int INF = 2e9;
const LL LNF = 9e18;
const int mod = 1e9+;
const int maxn = +; int n, a[][], sta[maxn], val[maxn], dp[][maxn];
int tot; int cal(int r, int state)
{
int sum = ;
for(int i = ; state>; state>>=, i++)
if(state&)
sum += a[r][i];
return sum;
} int main()
{
while(scanf("%d",&n)!=EOF)
{
for(int i = ; i<=n; i++)
for(int j = ; j<=n; j++)
scanf("%d",&a[i][j]); tot = ;
for(int i = ; i<(<<n); i++)
if((i&(i<<))==)
sta[++tot] = i; memset(dp, , sizeof(dp));
for(int r = ; r<=n; r++)
{
for(int j = ; j<=tot; j++)
for(int k = ; k<=tot; k++)
{
if((sta[j]&sta[k])==)
dp[r][j] = max(dp[r][j], dp[r-][k]+ cal(r,sta[j]));
}
} int ans = ;
for(int i = ; i<=tot; i++)
if(dp[n][i]>ans)
ans = max(ans, dp[n][i]); printf("%d\n",ans);
}
return ;
}

逐格递推(轮廓线更新):

 #include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
#include <cmath>
#include <queue>
#include <stack>
#include <map>
#include <string>
#include <set>
using namespace std;
typedef long long LL;
const int INF = 2e9;
const LL LNF = 9e18;
const int MOD = 1e9+;
const int MAXN = 1e5;
const int HASH = 1e4; int n, val[][], dp[][<<]; int main()
{
while(scanf("%d", &n)!=EOF)
{
for(int i = ; i<n; i++)
for(int j = ; j<n; j++)
scanf("%d", &val[i][j]); int cur = ;
for(int s = ; s<(<<n); s++)
dp[cur][s] = -INF;
dp[cur][] = ; for(int i = ; i<n; i++)
for(int j = ; j<n; j++)
{
memset(dp[cur^], , sizeof(dp[cur^]));
for(int s = ; s<(<<n); s++)
{
bool hav_up = s&(<<j);
bool hav_left = false;
if(j) hav_left = s&(<<(j-)); if(!hav_up && !hav_left)
{
dp[cur^][s^(<<j)] = max(dp[cur^][s^(<<j)], dp[cur][s]+val[i][j]); //取
dp[cur^][s] = max(dp[cur^][s], dp[cur][s]); //不取
}
//由于相邻的格子已经去了,故此格子不能取
else if(hav_left && !hav_up)
dp[cur^][s] = max(dp[cur^][s], dp[cur][s]);
else if(!hav_left && hav_up)
dp[cur^][s^(<<j)] = max(dp[cur^][s^(<<j)], dp[cur][s]);
else
dp[cur^][s^(<<j)] = max(dp[cur^][s^(<<j)], dp[cur][s]);
}
cur ^= ;
} int ans = ;
for(int s = ; s<(<<n); s++)
ans = max(ans, dp[cur][s]);
printf("%d\n", ans);
}
}

简化后:

 #include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
#include <cmath>
#include <queue>
#include <stack>
#include <map>
#include <string>
#include <set>
using namespace std;
typedef long long LL;
const int INF = 2e9;
const LL LNF = 9e18;
const int MOD = 1e9+;
const int MAXN = 1e5;
const int HASH = 1e4; int n, val[][], dp[][<<]; int main()
{
while(scanf("%d", &n)!=EOF)
{
for(int i = ; i<n; i++)
for(int j = ; j<n; j++)
scanf("%d", &val[i][j]); int cur = ;
for(int s = ; s<(<<n); s++)
dp[cur][s] = -INF;
dp[cur][] = ; for(int i = ; i<n; i++)
for(int j = ; j<n; j++)
{
memset(dp[cur^], , sizeof(dp[cur^]));
for(int s = ; s<(<<n); s++)
{
int up = s&(<<j);
int left = ;
if(j) left = s&(<<(j-)); dp[cur^][s^up] = max(dp[cur^][s^up], dp[cur][s]); //不取. (异或功能强大)
if(!up && !left) //取,前提是相邻格没有取
dp[cur^][s^(<<j)] = max(dp[cur^][s^(<<j)], dp[cur][s]+val[i][j]);
}
cur ^= ;
} int ans = ;
for(int s = ; s<(<<n); s++)
ans = max(ans, dp[cur][s]);
printf("%d\n", ans);
}
}

轮廓线更新 + 哈希表:

 #include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
#include <cmath>
#include <queue>
#include <stack>
#include <map>
#include <string>
#include <set>
using namespace std;
typedef long long LL;
const int INF = 2e9;
const LL LNF = 9e18;
const int MOD = 1e9+;
const int MAXN = 1e5;
const int HASH = 1e4; int n, val[][]; struct
{
int size, head[HASH], next[MAXN];
int state[MAXN], sum[MAXN]; void init()
{
size = ;
memset(head, -, sizeof(head));
} void insert(int status, int Sum)
{
int u = status%HASH;
for(int i = head[u]; i!=-; i = next[i])
{
if(state[i]==status)
{
sum[i] = max(sum[i], Sum);
return;
}
}
state[size] = status; //头插法
sum[size] = Sum;
next[size] = head[u];
head[u] = size++;
} }Hash_map[]; int main()
{
while(scanf("%d", &n)!=EOF)
{
for(int i = ; i<n; i++)
for(int j = ; j<n; j++)
scanf("%d", &val[i][j]); int cur = ;
Hash_map[cur].init();
Hash_map[cur].insert(, );
for(int i = ; i<n; i++)
for(int j = ; j<n; j++)
{
Hash_map[cur^].init();
for(int k = ; k<Hash_map[cur].size; k++)
{
int status = Hash_map[cur].state[k];
int Sum = Hash_map[cur].sum[k]; int up = status&(<<j);
int left = ;
if(j) left = status&(<<(j-)); Hash_map[cur^].insert(status^up, Sum); //不取
if(!up && !left) //取,前提是相邻的格子没有取
Hash_map[cur^].insert(status^(<<j), Sum+val[i][j]);
}
cur ^= ;
} int ans = ;
for(int k = ; k<Hash_map[cur].size; k++)
ans = max(ans, Hash_map[cur].sum[k]);
printf("%d\n", ans);
}
}

二分图点带权最大独立集(最小割最大流):

HDU1569 方格取数(2)

HDU1565 方格取数(1) —— 状压DP or 插头DP(轮廓线更新) or 二分图点带权最大独立集(最小割最大流)的更多相关文章

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

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

  2. hdu 2167 方格取数 【状压dp】(经典)

    <题目链接> 题目大意: 给出一些数字组成的n*n阶矩阵,这些数字都在[10,99]内,并且这个矩阵的  3<=n<=15,从这个矩阵中随机取出一些数字,在取完某个数字后,该数 ...

  3. HDU1565 方格取数 &&uva 11270 轮廓线DP

    方格取数(1) Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Su ...

  4. Hdu-1565 方格取数(1) (状态压缩dp入门题

    方格取数(1) Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total S ...

  5. HDU-1565 方格取数(1)

    http://acm.hdu.edu.cn/showproblem.php?pid=1565 方格取数(1) Time Limit: 10000/5000 MS (Java/Others)    Me ...

  6. HDU1565 方格取数1(构图+网络流最大独立集合)

    题目大意:给你一个n*n的格子的棋盘,每个格子里面有一个非负数. 从中取出若干个数,使得任意的两个数所在的格子没有公共边,就是说所取的数所在的2个格子不能相邻,并且取出的数的和最大. 解题思路:最大点 ...

  7. HDU1569 方格取数(2) —— 二分图点带权最大独立集、最小割最大流

    题目链接:https://vjudge.net/problem/HDU-1569 方格取数(2) Time Limit: 10000/5000 MS (Java/Others)    Memory L ...

  8. HDU1565 方格取数(1)(状态压缩dp)

    题目链接. 分析: 说这题是状态压缩dp,其实不是,怎么说呢,题目数据太水了,所以就过了.手动输入n=20的情况,超时.正解是网络流,不太会. A这题时有个细节错了,是dp[i][j]还是dp[i][ ...

  9. HDU1565方格取数

    典型的状态压缩DP问题.第i行的取法只受到第i-1行的影响.首先每一行的取法要相容(不能有两个相邻),然后相邻行之间也要相容.将每一个格子看做两种状态,1表示取,0表示不取.这样每一行就是一个01串, ...

随机推荐

  1. UVa10214 Trees in a Wood.

    先算第一象限能看到的树,答案乘以4就是四个象限的数的总数,再加上坐标轴上四棵树,就是总共能看到的树. 树的总数为(2*a+1)*(2*b+1)-1  ←矩形面积除去原点位置 设一棵树的坐标是(x,y) ...

  2. linux与windows查看占用端口的进程ID并杀死进程

    有时候tomcat出现端口被占用,需要查出进程ID并杀死进程. 1.查找占用端口的进程ID(windows与linux一样  8005也可以加上引号   grep可以用findstr替换) 6904就 ...

  3. 【调试】JS断点调试

    1.断点调试是啥?难不难? 断点调试其实并不是多么复杂的一件事,简单的理解无外呼就是打开浏览器,打开sources找到js文件,在行号上点一下罢了.操作起来似乎很简单,其实很多人纠结的是,是在哪里打断 ...

  4. UI小结

    第一.UIButton的定义      UIButton *button=[[UIButton buttonWithType:(UIButtonType); 能够定义的button类型有以下6种,   ...

  5. MyBatis的参数,不能传入null

    今天在调试的过程中发现一个bug,把传入的参数写到查询分析器中执行没有问题,但是在程序中执行就报错:org.springframework.jdbc.UncategorizedSQLException ...

  6. hdu 4975 A simple Gaussian elimination problem 最大流+找环

    原题链接 http://acm.hdu.edu.cn/showproblem.php?pid=4975 这是一道很裸的最大流,将每个点(i,j)看作是从Ri向Cj的一条容量为9的边,从源点除法连接每个 ...

  7. 【Java TCP/IP Socket】Java NIO Socket VS 标准IO Socket

    简介 Java  NIO从JDK1.4引入,它提供了与标准IO完全不同的工作方式. NIO包(java.nio.*)引入了四个关键的抽象数据类型,它们共同解决传统的I/O类中的一些问题.    1. ...

  8. 修复OS X的Finder中文档 打开方式中重复程序的问题

    如上图,OS X在使用一段时间后,有些软件就会重复注册打开方式,对于有洁癖的人,这是难以接受的事. 不过有个命令可以很简单的把重复项给去掉. /System/Library/Frameworks/Co ...

  9. Solidworks如何绘制标准螺纹线

    1 绘制螺旋线,螺距为0.5mm,圈数为15,起始角度为0°.   2                

  10. HDU 3820 Golden Eggs( 最小割 奇特建图)经典

    Golden Eggs Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Tota ...