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,可以定义 ...
随机推荐
- Linux Docker Introduction
Setup on Ubuntu. 前提条件: Docker需要两个重要的安装要求: 它仅适用于64位Linux安装,注意:是64位的Linux系统. 它需要Linux内核版本3.10或更高版本. 要查 ...
- 什么是PHP?
PHP起源于1995年,由Rasmus Lerdorf开发.到现在,PHP已经历了21年的时间洗涤,成为全球最受欢迎的脚本开发语言之一.由于PHP 5是一种面向对象.完全跨平台的新型Web开发语言.所 ...
- DRF框架(七) ——三大认证组件之频率组件、jwt认证
drf频率组件源码 1.APIView的dispatch方法的 self.initial(request,*args,**kwargs) 点进去 2.self.check_throttles(re ...
- 在local模式下的spark程序打包到集群上运行
一.前期准备 前期的环境准备,在Linux系统下要有Hadoop系统,spark伪分布式或者分布式,具体的教程可以查阅我的这两篇博客: Hadoop2.0伪分布式平台环境搭建 Spark2.4.0伪分 ...
- Oracle数据库 常用的触发器命令
创建自增序列,创建触发器(在触发时间中操纵序列,实现主键自增): Oracle数据库不支持自增方法 create sequence seq_userInfo_usid start with ;--创建 ...
- Openstack Sahara组件和架构简介
1.简介 Apache Hadoop是目前被广泛使用的主流大数据处理计算框架,Sahara项目旨在使用用户能够在Openstack平台上便于创建和管理Hadoop以及其他计算框架集群,实现类似AWS的 ...
- angular复习笔记3-组件
组件Component 组件是构成angular应用的核心,angular的有序运行依赖于组件的协同工作,组件之于angular应用就像是汽车和汽车零部件的意思. 概述 近几年的前端发展迅速,各种工程 ...
- Thymeleaf前后端分页查询
分页查询是一个很常见的功能,对于分页也有很多封装好的轮子供我们使用. 比如使用mybatis做后端分页可以用Pagehelper这个插件,如果使用SpringDataJPA更方便,直接就内置的分页查询 ...
- SAP Hybris Discount group,折扣组,折扣记录,用户组几组概念的关联
在backoffice的Price Settings->Discount->Customer Discount Groups菜单下面,创建一个新的Customer Discount Gro ...
- Cypress自动化环境搭建
1.Cypress 下载: 官网下载,下载后直接解压即可,解压后便可单机exe文件打开 Ps:直接打开exe是会报错找不到json文件的,所以还要安装依赖环境 运行cypress项目前,必须vue-c ...