HDU1565 方格取数(1) —— 状压DP or 插头DP(轮廓线更新) or 二分图点带权最大独立集(最小割最大流)
题目链接: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
从中取出若干个数,使得任意的两个数所在的格子没有公共边,就是说所取的数所在的2个格子不能相邻,并且取出的数的和最大。
75 15 21
75 15 28
34 70 5
逐行递推:
#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 二分图点带权最大独立集(最小割最大流)的更多相关文章
- HDU 1565 - 方格取数(1) - [状压DP][网络流 - 最大点权独立集和最小点权覆盖集]
题目链接:https://cn.vjudge.net/problem/HDU-1565 Time Limit: 10000/5000 MS (Java/Others) Memory Limit: 32 ...
- hdu 2167 方格取数 【状压dp】(经典)
<题目链接> 题目大意: 给出一些数字组成的n*n阶矩阵,这些数字都在[10,99]内,并且这个矩阵的 3<=n<=15,从这个矩阵中随机取出一些数字,在取完某个数字后,该数 ...
- HDU1565 方格取数 &&uva 11270 轮廓线DP
方格取数(1) Time Limit: 10000/5000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total Su ...
- Hdu-1565 方格取数(1) (状态压缩dp入门题
方格取数(1) Time Limit: 10000/5000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) Total S ...
- HDU-1565 方格取数(1)
http://acm.hdu.edu.cn/showproblem.php?pid=1565 方格取数(1) Time Limit: 10000/5000 MS (Java/Others) Me ...
- HDU1565 方格取数1(构图+网络流最大独立集合)
题目大意:给你一个n*n的格子的棋盘,每个格子里面有一个非负数. 从中取出若干个数,使得任意的两个数所在的格子没有公共边,就是说所取的数所在的2个格子不能相邻,并且取出的数的和最大. 解题思路:最大点 ...
- HDU1569 方格取数(2) —— 二分图点带权最大独立集、最小割最大流
题目链接:https://vjudge.net/problem/HDU-1569 方格取数(2) Time Limit: 10000/5000 MS (Java/Others) Memory L ...
- HDU1565 方格取数(1)(状态压缩dp)
题目链接. 分析: 说这题是状态压缩dp,其实不是,怎么说呢,题目数据太水了,所以就过了.手动输入n=20的情况,超时.正解是网络流,不太会. A这题时有个细节错了,是dp[i][j]还是dp[i][ ...
- HDU1565方格取数
典型的状态压缩DP问题.第i行的取法只受到第i-1行的影响.首先每一行的取法要相容(不能有两个相邻),然后相邻行之间也要相容.将每一个格子看做两种状态,1表示取,0表示不取.这样每一行就是一个01串, ...
随机推荐
- Min(BZOJ 1441)
题目描述 给出n个数(A1...An)现求一组整数序列(X1...Xn)使得S=A1*X1+...An*Xn>0,且S的值最小 输入 第一行给出数字N,代表有N个数 下面一行给出N个数 输出 S ...
- ElasticSearch API 之 DELETE
删除API,可以根据特定的ID删除文档. $ curl -XDELETE 'http://localhost:9200/website/blog/AVbkih8AltSLRRB7XAun' 会返回下面 ...
- 【Codeforces Round #502 (Div. 1 + Div. 2) 】
A:https://www.cnblogs.com/myx12345/p/9843032.html B:https://www.cnblogs.com/myx12345/p/9843050.html ...
- BZOJ4726: [POI2017]Sabota?
$n \leq 500000$的树,开始有一个点是坏的,如果一个子树中坏点比例(不包括根节点)超过x那这整棵子树就会变坏,问最坏情况下不超过$K$个坏点的情况下$x$最小是多少. 被坑成傻逼.. 可以 ...
- grequests----golang的requests库
github.com/levigross/grequests: A Go "clone" of the great and famous Requests library 特点: ...
- POJ 1991 Turning in Homework(区间DP)
题目链接 Turning in Homework 考虑区间DP $f[i][j][0]$为只考虑区间$[i, j]$且最后在$a[i]$位置交作业的答案. $f[i][j][1]$为只考虑区间$[i, ...
- vue之监听事件
一.v-on 可以用 v-on 指令监听 DOM 事件,并在触发时运行一些 JavaScript 代码. 简写形式 用@代替 v-on: <button v-on:click="co ...
- LCD1602和LCD12864
1602 字符型(字符型的模组) 只能显示数字与字符,不可以显示汉字 12864 点阵型(图形型的模组) 可根据需求任意显示字符 数字 汉字 图形 1602 为16字乘2行12864 为128列点阵乘 ...
- Effective Java P2 Item1 Consider static factory methods instead of constructors
获得一个类的实例的传统方法是公共的构造方法,还可以提供一个公共的静态工厂方法(一个返回值为该类实例的简单静态方法), 例如Boolean(boolean 的封装类) public static Boo ...
- XML Publisher Template Type - Microsoft Excel Patch
XML Publisher Template Type - Microsoft Excel Patch Oracle XML Publisher > Templates > Create ...