[HNOI 2007]神奇游乐园

#include <bits/stdc++.h>
#define maxn 110
using namespace std;
typedef long long ll;
int n, m;
int a[maxn][maxn];
ll ans = -1ll << 60;
#define M 2000010
#define mod 997 struct Hashmap{ ll st[M];
int h[1000], size, nxt[M];
ll f[M];
void clear(){memset(h, 0, sizeof h); size = 0;}
void push(ll hash_, ll val){
int tmp = hash_ % mod;
for(int i = h[tmp]; i; i = nxt[i]){
if(st[i] == hash_){
f[i] = max(f[i], val);
return;
}
}
int now = ++ size;
f[now] = val;
st[now] = hash_;
nxt[now] = h[tmp];
h[tmp] = now;
}
}dp[2]; int cur, code[20], ch[20]; void Decode(ll st){
for(int i = m; i >= 0; i --)
code[i] = st & 7, st >>= 3;
} ll Encode(){
ll ret = 0;
memset(ch, -1, sizeof ch);
ch[0] = 0; int cnt = 0;
for(int i = 0; i <= m; i ++){
if(ch[code[i]] == -1)ch[code[i]] = ++ cnt;
code[i] = ch[code[i]];
ret = ret << 3 | code[i];
}
return ret;
} void Shift(){
for(int i = m; i >= 1; i --)
code[i] = code[i-1];
code[0] = 0;
} inline void Change(int u, int v){
for(int i = 0; i <= m; i ++)
if(code[i] == v)
code[i] = u;
} void DP(int i, int j){
dp[cur^1].clear();
for(int k = 1; k <= dp[cur].size; k ++){
Decode(dp[cur].st[k]);
if(j == 1){if(code[m])continue;Shift();}
int Left = code[j-1], Up = code[j];
if(Left && Up){
code[j] = code[j-1] = 0;
if(Left == Up){
ll ENCODE = Encode();
if(ENCODE == 0)ans = max(ans, dp[cur].f[k] + a[i][j]);
}
else{
Change(Left, Up);
dp[cur^1].push(Encode(), dp[cur].f[k] + a[i][j]);
}
}
else if(Left || Up){
int tmp = Left ? Left : Up;
code[j-1] = 0, code[j] = tmp;
dp[cur^1].push(Encode(), dp[cur].f[k] + a[i][j]);
code[j] = 0, code[j-1] = tmp;
dp[cur^1].push(Encode(), dp[cur].f[k] + a[i][j]);
}
else{
dp[cur^1].push(Encode(), dp[cur].f[k]);
code[j] = code[j-1] = 8;
dp[cur^1].push(Encode(), dp[cur].f[k] + a[i][j]);
}
}
cur ^= 1;
} int main(){
#ifndef ONLINE_JUDGE
freopen("park.in","r",stdin);
freopen("park.out","w",stdout);
#endif
scanf("%d%d", &n, &m);
for(int i = 1; i <= n; i ++)
for(int j = 1; j <= m; j ++)
scanf("%d", &a[i][j]);
dp[cur].clear();
dp[cur].push(0, 0);
for(int i = 1; i <= n; i ++)
for(int j = 1; j <= m; j ++)
DP(i, j); printf("%lld\n", ans);
return 0;
}

粘了一个模板上来=-=

基于连通性的动态规划,最小表示法很好用。

我们可以用一个压缩的数字表示一个连通情况,比如DP生成树,概率,棋盘上格子的情况,等等等

只要和连通性有关而且n很小时就可以用啦QAQ。

又忘了模板了QAQ

就是如果左边和上面是一个连通分量即Left == Up时,我们要合并连通分量,所以此时已经出现了一个圈了,这道题不能有多个圈,所以最后不放进去

code[j] = code[j-1] = 0.

[BZOJ 3753]Wall

扩展一下方格变成一个回路问题,然后射线法判断格子是否内部。

出现的问题是当left == up时,code[j] = code[j-1] = 0,然后再改所有的标号

当必须只能有一个回路的时候,Encode()一定要等于0.

#include <bits/stdc++.h>
#define maxn 20
using namespace std;
typedef long long ll;
int n, m; int need[maxn][maxn], a[maxn][maxn]; int cur = 0, Cnt, cnt; const int md = 997; struct Hashmap{
#define M 2000010
ll st[M];
int f[M], h[1000], nxt[M], size;
void init(){
memset(h, 0, sizeof h);
size = 0;
}
void push(ll hs, int val){
int tmp = hs % md;
for(int i = h[tmp]; i; i = nxt[i]){
if(st[i] == hs){
f[i] = max(f[i], val);
return;
}
}
int now = ++ size;
f[now] = val;
nxt[now] = h[tmp];
st[now] = hs;
h[tmp] = now;
}
}dp[2]; int code[maxn], ch[maxn]; void Decode(ll st){
for(int i = m; i >= 0; i --)
code[i] = st & 7, st >>= 3;
} ll Encode(){
ll ret = 0;
memset(ch, -1, sizeof ch);
ch[0] = 0; int cnt = 0;
for(int i = 0; i <= m; i ++){
if(ch[code[i]] == -1)
ch[code[i]] = ++ cnt;
code[i] = ch[code[i]];
ret <<= 3;
ret |= code[i];
}return ret;
} void Shift(){
for(int i = m; i; i --)
code[i] = code[i-1];
code[0] = 0;
} bool Judge(int cnt, int i, int j){
if(cnt && need[i][j] == 1)return false;
if(!cnt && need[i][j] == 2)return false;
return true;
} int ans = -0x7fffffff; void Trans(int i, int j){
dp[cur^1].init();
for(int k = 1; k <= dp[cur].size; k ++){
Decode(dp[cur].st[k]);
if(j == 1){if(code[m])continue;Shift();}
int lf = code[j-1], up = code[j], sta = 0;
for(int p = 0; p < j-1; p ++)
sta ^= (code[p] != 0);
if(lf && up){
code[j] = code[j-1] = 0;
if(lf == up){
if(Encode() == 0 && cnt == Cnt)//here!
ans = max(ans, dp[cur].f[k]);
}
else{
if(Judge(sta, i, j)){
for(int p = 0; p <= m; p ++)
if(code[p] == up)
code[p] = lf;
dp[cur^1].push(Encode(), dp[cur].f[k] + sta * a[i][j]);
}
}
}
else if(lf || up){
int tmp = lf ? lf : up;
if(Judge(sta, i, j)){
code[j-1] = 0, code[j] = tmp;
dp[cur^1].push(Encode(), dp[cur].f[k] + sta * a[i][j]);
}
sta ^= 1;
if(Judge(sta, i, j)){
code[j] = 0, code[j-1] = tmp;
dp[cur^1].push(Encode(), dp[cur].f[k] + sta * a[i][j]);
}
}
else{
if(Judge(sta, i, j))
dp[cur^1].push(Encode(), dp[cur].f[k] + sta * a[i][j]);
sta ^= 1;
if(Judge(sta, i, j)){
code[j] = code[j-1] = 15;
dp[cur^1].push(Encode(), dp[cur].f[k] + sta * a[i][j]);
}
}
}
if(need[i][j] == 2)cnt ++;
cur ^= 1;
} int main(){
scanf("%d%d", &n, &m);
for(int i = 1; i <= n; i ++)
for(int j = 1; j <= m; j ++)
scanf("%d", &a[i][j]);
n ++, m ++;
dp[cur].init();
dp[cur].push(0, 0);
for(int i = 1; i <= n; i ++)
for(int j = 1; j <= m; j ++)
Trans(i, j);
printf("%d\n", ans); for(int i = 1; i < n; i ++)
for(int j = 1; j < m; j ++)
scanf("%d", &need[i][j]), Cnt += need[i][j] == 2;
ans = -0x7fffffff;
dp[cur].init();
dp[cur].push(0, 0);
for(int i = 1; i <= n; i ++)
for(int j = 1; j <= m; j ++)
Trans(i, j);
if(ans < -0x7ffffff)printf("Can not establish GFW.");
else printf("%d\n", ans);
return 0;
}

[插头DP自我总结]的更多相关文章

  1. 【BZOJ2310】ParkII 插头DP

    [BZOJ2310]ParkII Description Hnoi2007-Day1有一道题目 Park:给你一个 m * n 的矩阵,每个矩阵内有个权值V(i,j) (可能为负数),要求找一条回路, ...

  2. 【Learning】插头DP

    简介 插头DP(轮廓线DP)是用来解决网格图回路问题的一种算法. 插头DP解决的经典问题就是统计经过所有格子的哈密顿回路条数,某些格子有障碍. ​ 如果问题稍微进阶一点的话,不一定要求路径是回路.路径 ...

  3. 插头dp

    插头dp 感受: 我觉得重点是理解,算法并不是直接想出怎样由一种方案变成另一种方案.而是方案本来就在那里,我们只是枚举状态统计了答案. 看看cdq的讲义什么的,一开始可能觉得状态很多,但其实灰常简单 ...

  4. HDU 4113 Construct the Great Wall(插头dp)

    好久没做插头dp的样子,一开始以为这题是插头,状压,插头,状压,插头,状压,插头,状压,无限对又错. 昨天看到的这题. 百度之后发现没有人发题解,hust也没,hdu也没discuss...在acm- ...

  5. HDU 4949 Light(插头dp、位运算)

    比赛的时候没看题,赛后看题觉得比赛看到应该可以敲的,敲了之后发现还真就会卡题.. 因为写完之后,无限TLE... 直到后来用位运算代替了我插头dp常用的decode.encode.shift三个函数以 ...

  6. 插头DP专题

    建议入门的人先看cd琦的<基于连通性状态压缩的动态规划问题>.事半功倍. 插头DP其实是比较久以前听说的一个东西,当初是水了几道水题,最近打算温习一下,顺便看下能否入门之类. 插头DP建议 ...

  7. HDU 1693 Eat the Trees(插头DP、棋盘哈密顿回路数)+ URAL 1519 Formula 1(插头DP、棋盘哈密顿单回路数)

    插头DP基础题的样子...输入N,M<=11,以及N*M的01矩阵,0(1)表示有(无)障碍物.输出哈密顿回路(可以多回路)方案数... 看了个ppt,画了下图...感觉还是挺有效的... 参考 ...

  8. HDU 1693 Eat the Trees(插头DP)

    题目链接 USACO 第6章,第一题是一个插头DP,无奈啊.从头看起,看了好久的陈丹琦的论文,表示木看懂... 大体知道思路之后,还是无法实现代码.. 此题是插头DP最最简单的一个,在一个n*m的棋盘 ...

  9. HDU 4064 Carcassonne(插头DP)(The 36th ACM/ICPC Asia Regional Fuzhou Site —— Online Contest)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4064 Problem Description Carcassonne is a tile-based ...

随机推荐

  1. 2模02day1题解

    源文件在我的网盘上.链接:http://pan.baidu.com/s/1qWPUDRm 密码:k52e (只有机智的人才能看到我的链接) 机智的双重下划线~~~ T1 T1就是一个递推,这题目把我恶 ...

  2. 用php实现百度网盘图片直链的代码分享

    第一种代码:代码量较少通过正则表达式获取百度网盘的文件真实地址,来实现直链的效果 将下面的代码保存为downbd.php 复制代码代码如下: <?php $canshu=$_SERVER[&qu ...

  3. js获取文本框输入的值

    <script type="text/javascript"> function getPosition(obj) { ; if (obj.selectionStart ...

  4. local variable 'xxx' referenced before assignment

    这个问题很囧,在外面定义了一个变量 xxx ,然后在python的一个函数或类里面引用这个变量,并改变它的值,结果报错local variable 'xxx' referenced before as ...

  5. Android数据存储之SQLite的操作

    Android作为一个应用在移动设备上的操作系统,自然也就少不了数据的存储.然而SQLite作为一个轻型的关系型数据库,基于其轻量.跨平台.多语言接口及安全性等诸多因数考虑,因而Android较大的数 ...

  6. DP:Space Elevator(POJ 2392)

    太空电梯 题目大意:一群牛想造电梯到太空,电梯都是由一个一个块组成的,每一种块不能超过这个类型的高度,且每一种块都有各自的高度,有固定数量,问最高能造多高. 这题就是1742的翻版,对ai排个序就可以 ...

  7. Gym 100801A Alex Origami Squares (求正方形边长)

    题目:传送门.(需要下载PDF) 题意:给定一个长方形,在长方形内部画三个相同的正方形,问正方形的边长最大是多大. 题解:根据长宽比例可以算出三种情况,如果长比宽大三倍以上,那么正方形边长就是宽:如果 ...

  8. android之phonegap入门

    利用phoneGap可以利用HTML开发安卓应用,是web app的一种,可以有效的提高开发效率,降低开发成本 . 第一步: 开发环境配置以及基本操作请参考其它文档. 新增一个名为 phoneGap ...

  9. SQL 外键

    先新建2个表,写入数据 -- 创建测试主表. ID 是主键. CREATE TABLE test_main ( id INT, value ), PRIMARY KEY(id) ); -- 创建测试子 ...

  10. THINKPHP 默认模板路径替换

    APP_PATH // 当前项目目录APP_NAME // 当前项目名称 ACTION_NAME // 当前操作名称 CACHE_PATH // 项目模版缓存目录 CONFIG_PATH //项目配置 ...