HDU - 5513 Efficient Tree(轮廓线DP)
前言
- 最近学了基于连通性的状压DP,也就是插头DP,写了几道题,发现这DP实质上就是状压+分类讨论,轮廓线什么的也特别的神奇。下面这题把我WA到死…
HDU-5531 Efficient Tree
给出一个n∗mn*mn∗m的网格图,以及相邻四联通格子之间的边权。
对于命题xxx,如果xxx成立,那么 [x]=1[x]=1[x]=1,否则 [x]=0[x]=0[x]=0
对于一颗生成树,每个点的贡献为 1+[有一条连向上的边]+[有一条连向左的边]1+[有一条连向上的边]+[有一条连向左的边]1+[有一条连向上的边]+[有一条连向左的边]。这棵树的贡献为所有点的贡献之积。要求:- 最小生成树的边权和
- 所有最小生成树的贡献之和。
n<=800,m<=7n<=800, m<=7n<=800,m<=7
由于mmm最大只有777,考虑轮廓线DP:
- f(i,j,S)f(i,j,S)f(i,j,S) 表示当前在 (i,j)(i,j)(i,j)这个点,轮廓线上方的格子联通情况为SSS的边权之和
- g(i,j,S)g(i,j,S)g(i,j,S) 表示当前在 (i,j)(i,j)(i,j)这个点,轮廓线上方的格子联通情况为SSS的贡献之和

- 黄色格子就是当前考虑的点,蓝色部分就是上一次状压的 mmm 个格子
- 此处的SSS是用最小表示法状压的,状态是长度为 mmm 的 888 进制数,每个位置上的值表示每一个蓝色格子在哪一个联通块里
- 这里的状压与普通插头DP有点不同,普通插头DP的状态长度是m+1m+1m+1,因为多算上了中间那一条竖着的轮廓线,而这里并不用。
转移比较简单,只要注意两点:
- 如果当前格子上面的格子在单独一个联通块,那么这条向上的边必须选,否则就无法形成一棵联通的树。
- 如果上面的格子和左边的格子在同一个联通块就不能合并,否则构成了一个环。
AC代码
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int MAXN = 805, MAXM = 10;
const int HASH = 10007, NUM = 1000005;
const int mod = 1e9+7, inf = 0x3f3f3f3f;
struct node {
int w, sum;
node(int _w=0, int _sum=0):w(_w), sum(_sum){}
inline node operator +(const node &t)const {
if(w < t.w) return *this;
if(w > t.w) return t;
return node(w, (sum+t.sum)%mod);
}
inline node operator +(const int &t)const {
return node(w+t, sum);
}
inline node operator *(const int &t)const {
return node(w, 1ll*sum*t%mod);
}
};
int n, m;
int L[MAXN][MAXM], U[MAXN][MAXM];
struct HashMap {
int val[NUM], adj[HASH], pre[NUM], tot;
node f[NUM];
inline void init() {
memset(adj, -1, sizeof adj); tot = 0;
}
inline void insert(const int &x, const node &tmp) {
int u = x % HASH;
for(int i = adj[u]; ~i; i = pre[i])
if(val[i] == x) {
f[i] = f[i] + tmp; return;
}
val[++tot] = x; pre[tot] = adj[u]; adj[u] = tot; f[tot] = tmp;
}
}h[2];
int msk[MAXM], id[MAXM];
inline void decode(int x) {
for(int i = m; i; --i, x>>=3) msk[i] = x&7;
}
inline int encode(const int &m) {
int res = 0, cur = 0;
memset(id, -1, sizeof id);
id[0] = 0;
for(int i = 1; i <= m; ++i) {
if(id[msk[i]] == -1) id[msk[i]] = ++cur;
res = (res<<3)|id[msk[i]];
//注意这里不能 msk[i]=id[msk[i]], 否则改变了 msk[i]的值, dp函数中的x,y值就不对了
}
return res;
}
inline void dp(const int &i, const int &j, const int &now) {
for(int k = 1; k <= h[now^1].tot; ++k) {
decode(h[now^1].val[k]);
int x = msk[j-1], y = msk[j];
bool one = 1;
for(int l = 0; l <= m; ++l) //看是否是独立的联通块
if(l != j && msk[l] == y) { one = 0; break; }
if(!one) { //自成联通块
msk[j] = 8; //赋值为不可能出现的8
h[now].insert(encode(m), h[now^1].f[k]);
msk[j] = y;
}
if(i > 1)
h[now].insert(encode(m), (h[now^1].f[k] + U[i][j])*2);//只连左边
if(j > 1 && !one) {
msk[j] = x;
h[now].insert(encode(m), (h[now^1].f[k] + L[i][j])*2);//只连上边
msk[j] = y;
}
if(i > 1 && j > 1 && x != y) { //两边都连
for(int l = 0; l <= m; ++l) if(msk[l] == x) msk[l] = y;
h[now].insert(encode(m), (h[now^1].f[k] + L[i][j] + U[i][j])*3);
}
}
}
int main () {
int T;
scanf("%d", &T);
for(int kase = 1; kase <= T; ++kase) {
scanf("%d%d", &n, &m);
for(int i = 1; i <= n; ++i)
for(int j = 2; j <= m; ++j)
scanf("%d", &L[i][j]);
for(int i = 2; i <= n; ++i)
for(int j = 1; j <= m; ++j)
scanf("%d", &U[i][j]);
int now = 0; h[now].init(); h[now].insert(0, node(0, 1));
for(int i = 1; i <= n; ++i)
for(int j = 1; j <= m; ++j) {
now ^= 1; h[now].init();
dp(i, j, now);
}
node ans = node(inf, 0);
for(int i = 1; i <= h[now].tot; ++i) {
bool flag = 1;
decode(h[now].val[i]);
for(int j = 1; j < m; ++j)
if(msk[j] != msk[j+1]) { flag = 0; break; }
if(flag) ans = ans + h[now].f[i];
}
printf("Case #%d: %d %d\n", kase, ans.w, ans.sum);
}
}
PS:PS:PS:
我之所以WA就是因为encodeencodeencode函数里改变了mskmskmsk的值,出来后dpdpdp函数里的x,yx,yx,y就不对了,WA到自闭…
还有我的代码只用了msk[1...m]msk[1...m]msk[1...m],第000位没用
HDU - 5513 Efficient Tree(轮廓线DP)的更多相关文章
- HDU 5513 Efficient Tree
HDU 5513 Efficient Tree 题意 给一个\(N \times M(N \le 800, M \le 7)\)矩形. 已知每个点\((i-1, j)\)和\((i,j-1)\)连边的 ...
- hdu 5534 Partial Tree 背包DP
Partial Tree Time Limit: 20 Sec Memory Limit: 256 MB 题目连接 http://acm.hdu.edu.cn/showproblem.php?pid= ...
- HDU - 4804 Campus Design 轮廓线dp
题意:一个nm的矩阵被12的骨牌和11的骨牌完全覆盖,11的骨牌只能放c-d次,矩阵中有障碍物 题解:dp[i][j][k]表示到了第i行,第j个状态,放过k个11的骨牌,当前位有障碍物时只有一种转移 ...
- HDU 1565 方格取数(1) 轮廓线dp
题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=1565 方格取数(1) Time Limit: 10000/5000 MS (Java/Others) ...
- HDU 4802 && HDU 4803 贪心,高精 && HDU 4804 轮廓线dp && HDU 4805 计算几何 && HDU 4811 (13南京区域赛现场赛 题目重演A,B,C,D,J)
A.GPA(HDU4802): 给你一些字符串对应的权重,求加权平均,如果是N,P不计入统计 GPA Time Limit: 2000/1000 MS (Java/Others) Memory ...
- HDU - 4804 Campus Design(状压+轮廓线dp)
Campus Design Nanjing University of Science and Technology is celebrating its 60th anniversary. In o ...
- 2013 ACM-ICPC亚洲区域赛南京站C题 题解 轮廓线DP
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4804 题目大意 给你一个 \(n \times m\) 的矩形区域.你需要用 \(1 \times 1 ...
- 轮廓线DP POJ3254 && BZOJ 1087
补了一发轮廓线DP,发现完全没有必要从右往左设置状态,自然一点: 5 6 7 8 9 1 2 3 4 如此设置轮廓线标号,转移的时候直接把当前j位改成0或者1就行了.注意多记录些信息对简化代码是很有帮 ...
- HDU 1003 Max Sum --- 经典DP
HDU 1003 相关链接 HDU 1231题解 题目大意:给定序列个数n及n个数,求该序列的最大连续子序列的和,要求输出最大连续子序列的和以及子序列的首位位置 解题思路:经典DP,可以定义 ...
随机推荐
- thinkphp5 模板url标签 跟javascript ajax 的 url 参数 被莫名替换
发现一个 thinkphp5 的小bug 我用的是 thinkphp5.0.24 版本 在模板标签里 原来的大U函数 被改成url 那么问题来了 在javascript里 这样写 标签很容 ...
- Drool7s kmodule的作用--系列02课
本文是介绍drool7s kmodule. 一.为什么komdule.xml文件一定要放在resources下的META-INF文件夹中 --->直接看源码吧,请看下图,应该都知道为什么要放在固 ...
- Asp.net MVC 之ActionResult
ActionResult 派生出以下子类: ViewResult 返回一个网页视图 PartialViewResult 返回一个网页视图,但不适用布局页. ContentResult 返回一段字符串文 ...
- ASP.NET SignalR 系列(二)之项目创建
一.项目环境 IDE:VisualStudio 2015 SignalR 2.3.0 JQuery版本1.10.1 ,要求必须1.6.4以上 .net Framework 4.6 SignalR2.0 ...
- fulltext全文索引的使用
Fulltext全文索引 Fulltext相关属性 查看数据库关于fulltext的配置 SHOW VARIABLES LIKE 'ft%'; -- ft就是FullText的简写 ft_boolea ...
- (转载) @ConfigurationProperties 注解使用姿势,这一篇就够了
SpringBoot中的@ConfigurationProperties 传送门: http://www.hellojava.com/a/82613.html
- celery 定时任务,使用crontab表达式不执行(版本4.3.x)
celery 定时任务,使用crontab表达式不执行(版本4.3.x) 在使用celery 执行定时任务时,发现任务不会执行,schedule设置如下: 经测试,如果去掉hour,则任务每分钟都会执 ...
- 十二、vue中watch原理
1.普通的watch 2.对象属性的watch: 对象和数组都是引用类型,引用类型变量存的是地址,地址没有变,所以不会触发watch.这时我们需要进行深度监听,就需要加上一个属性 deep,值为 ...
- php正则表达式中preg_match_all函数的详解
php正则表达式中的函数我们之前为大家结果一个preg_match函数,相信大伙对此有所了解,那么php正则表达式中preg_match_all函数的具体使用是如何的呢?今天我们就带大家了解php正则 ...
- Android为TV端助力记录EditText.setInputType的坑
如XML中设置android:inputType=”numberDecimal”在Java代码中仅设置setInputType(EditorInfo.TYPE_NUMBER_FLAG_DECIMAL) ...