题目链接: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. LA 并查集路径压缩

    题目大意:有n个节点,初始时每个节点的父亲节点都不存在.有两种操作 I u v:把点节点u的父亲节点设为v,距离为|u-v|除以1000的余数.输入保证执行指令前u没有父亲节点. E u:询问u到根节 ...

  2. POJ2486 Apple Tree

    Time Limit: 1000MS   Memory Limit: 65536KB   64bit IO Format: %lld & %llu Description Wshxzt is ...

  3. *LOJ#2322. 「清华集训 2017」Hello world!

    $n \leq 50000$的树,有点权$\leq 1e13$,$q \leq 400000$次操作,有两种操作:从$s$跳到$t$每次$k$步,不到$k$步直接跳到$t$,每次把经过的点取根号:同样 ...

  4. HDU 4803 Poor Warehouse Keeper (贪心+避开精度)

    555555,能避开精度还是避开精度吧,,,,我们是弱菜.. Poor Warehouse Keeper Time Limit: 2000/1000 MS (Java/Others)    Memor ...

  5. Python入门--6--今天抄袭人家一篇日志--numpy这个

    Numpy NumPy的主要对象是同种元素的多维数组. 这是一个所有元素都是同一类型.通过一个正整数元祖索引的元素表格(通常元素都是数字) 在Numpy中维度(dimensions)叫做:轴 轴的个数 ...

  6. iOS APP 架构漫谈[转]

      Mark  一下 很不错的文章   最近看了一些有关server的东西,一些很简单的东西,不外乎是一些文档规范,另外结合最近看的wwdc的一些video,觉得对软件架构(software arch ...

  7. 最小费用最大流粗解 poj2516

    最小费用最大流,一般解法如下: 在流量基础上,每条边还有权费用,即单位流量下的所需费用.在最大流量下,求最小费用.解法:在最大流算法基础上,每次按可行流增广改为每次用spfa按最小费用(用单位费用)增 ...

  8. OC-Runtime温故知新

    每个java应用程序都有一个runtime类实例,使应用程序能够与其运行的环境相连接.可以通过getRuntime 方法获取当前运行时,应用程序不能自己创建runtime类实例.Runtime 没有构 ...

  9. 每日记录 2016-4-29 HTML5本地存储

    HTML5本地存储 一.HTML5 localStorage 在HTML5中,本地存储是一个window的属性,包括localStorage和 sessionStorage,从名字应该可以很清楚的辨认 ...

  10. 什么是Hadoop?什么是HDFS?

    [学习笔记] 什么是Hadoop?什么是HDFS?马 克-to-win @ 马克java社区:Hadoop是Apache基金会开发的一个分布式系统基础架构.比如前面我们接触的Spring就是一个开发应 ...