前言
  • 最近学了基于连通性的状压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&lt;=800,m&lt;=7n&lt;=800, m&lt;=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)的更多相关文章

  1. HDU 5513 Efficient Tree

    HDU 5513 Efficient Tree 题意 给一个\(N \times M(N \le 800, M \le 7)\)矩形. 已知每个点\((i-1, j)\)和\((i,j-1)\)连边的 ...

  2. hdu 5534 Partial Tree 背包DP

    Partial Tree Time Limit: 20 Sec Memory Limit: 256 MB 题目连接 http://acm.hdu.edu.cn/showproblem.php?pid= ...

  3. HDU - 4804 Campus Design 轮廓线dp

    题意:一个nm的矩阵被12的骨牌和11的骨牌完全覆盖,11的骨牌只能放c-d次,矩阵中有障碍物 题解:dp[i][j][k]表示到了第i行,第j个状态,放过k个11的骨牌,当前位有障碍物时只有一种转移 ...

  4. HDU 1565 方格取数(1) 轮廓线dp

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

  5. 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 ...

  6. HDU - 4804 Campus Design(状压+轮廓线dp)

    Campus Design Nanjing University of Science and Technology is celebrating its 60th anniversary. In o ...

  7. 2013 ACM-ICPC亚洲区域赛南京站C题 题解 轮廓线DP

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4804 题目大意 给你一个 \(n \times m\) 的矩形区域.你需要用 \(1 \times 1 ...

  8. 轮廓线DP POJ3254 && BZOJ 1087

    补了一发轮廓线DP,发现完全没有必要从右往左设置状态,自然一点: 5 6 7 8 9 1 2 3 4 如此设置轮廓线标号,转移的时候直接把当前j位改成0或者1就行了.注意多记录些信息对简化代码是很有帮 ...

  9. HDU 1003 Max Sum --- 经典DP

    HDU 1003    相关链接   HDU 1231题解 题目大意:给定序列个数n及n个数,求该序列的最大连续子序列的和,要求输出最大连续子序列的和以及子序列的首位位置 解题思路:经典DP,可以定义 ...

随机推荐

  1. 【转帖】LSM树 和 TSM存储引擎 简介

    LSM树 和 TSM存储引擎 简介 2019-03-08 11:45:23 长烟慢慢 阅读数 461  收藏 更多 分类专栏: 时序数据库   版权声明:本文为博主原创文章,遵循CC 4.0 BY-S ...

  2. Java学习之旅(二):生病的狗2(java例化)

    废话不多说,直接上肝货,可运行. 代码简陋,逻辑关系可能还不是很严谨,欢迎交流. public class Owner { //属性部分 //狗主人肯定有一条狗,这条狗可以被别的主人检查,所以设置为p ...

  3. C++ 工程师养成 每日一题4.5 (迭代器遍历)

    首先说明,当每日一题标号不是整数时代表此题是较为简单的,我在这里整理一遍主要是我做错了(没错是我太菜各位大佬无视就好) 题目: 读入一个字符串str,输出字符串str中的连续最长的数字串 此题思路清晰 ...

  4. 在js中使用for和forEach遍历数组

    数组的遍历 for var arr = [1, 2, 3, 4]; for (var i = 0; i < arr.length; i++){ arr[i]; } forEach var arr ...

  5. Python-MySQL学习

    内容来源(有删改):https://blog.csdn.net/hzw6991/article/details/87893761 上面链接同步视频地址:https://www.bilibili.com ...

  6. HBase 系列(三)—— HBase 基本环境搭建

    一.安装前置条件说明 1.1 JDK版本说明 HBase 需要依赖 JDK 环境,同时 HBase 2.0+ 以上版本不再支持 JDK 1.7 ,需要安装 JDK 1.8+ .JDK 安装方式见本仓库 ...

  7. 常用正则表达式和一些demo

    一.校验数字的表达式 数字:^[0-9]*$ n位的数字:^\d{n}$ 至少n位的数字:^\d{n,}$ m-n位的数字:^\d{m,n}$ 零和非零开头的数字:^(0|[1-9][0-9]*)$ ...

  8. JS-练习题

    1.foo()结果 function foo() { bar.apply(null, arguments); } function bar(){ console.log(arguments); } f ...

  9. Redhat下安装SAP的相关

    Red Hat Enterprise Linux 6.x: Installation and Upgrade - SAP Note 1496410 Red Hat Enterprise Linux 7 ...

  10. 深入理解jvm--分代回收算法通俗理解

    1.通俗的理解java对象的这一辈子 我是一个普通的java对象,我出生在Eden区,在Eden区我还看到和我长的很像的小兄弟,我们在Eden区中玩了挺长时间.有一天Eden区中的人实在是太多了,我就 ...