HDU 5513 Efficient Tree
HDU 5513 Efficient Tree
题意
- 给一个\(N \times M(N \le 800, M \le 7)\)矩形。
- 已知每个点\((i-1, j)\)和\((i,j-1)\)连边的花费,求最小生成树的权和。
- 对于每棵最小生成树\(T\),求\(\tau(T)=\prod{LRdeg_u}\)的和,其中\(LRdeg_u\)表示左、上方连边的个数+1。
思路
- 因为\(M\)很小,可以考虑轮廓线DP,记录前\(M\)个格子的连通信息。
- 对于每个格子\((i, j)\)有4种转移:
- 不与\((i, j-1)\)和\((i - 1, j)\)连边:此时\((i-1, j)\)的连通块不能被当前格子给挡住。
- 和\((i,j - 1)\)和\((i-1,j)\)都有连边:那么两个格子的连通块不能一样,否则会成环。
- 和\((i, j-1)\)连边:直接染色即可。
- 和\((i-1,j)\)连边:同1,不能挡住\((i-1,j)\)的连通块。
- 出现的几个问题:
- 之前写的都是简单回路和简单路径,所以每次转移只有其中一种,而做这道题应该每种都要考虑,并且每次转移前都要重新解码,否则信息会由于之前的转移发生改变。
- 需要再认真读几遍《基于连通性状态压缩的动态规划问题》这篇论文。
#include<cstdio>
#include<cstring>
#include<map>
#include<set>
#include<vector>
#include<iostream>
#include<algorithm>
using namespace std;
#define pb push_back
#define sz(x) ((int)(x).size())
#define rep(i,l,r) for(int i=(l);i<(r);++i)
typedef long long ll;
typedef pair<int, int> pii;
const int N = 1e5 + 7;
const int INF = 2e9 + 7;
const int MOD = 1e9 + 7;
//--------head--------
void inc(int &x, int y) {
x += y;
if (x >= MOD)
x -= MOD;
}
int S, cod[20], col[20];
void decode(int a[], int n, int st) {
for (int i = n; i >= 0; --i, st >>= 3)
a[i] = st & 7;
}
int encode(int a[], int n) {
int id = 0, st = 0;
memset(col, -1, sizeof(col)), col[0] = 0;
for (int i = 0; i <= n; ++i) {
if (col[a[i]] == -1)
col[a[i]] = ++id;
a[i] = col[a[i]];
st = (st << 3) | a[i];
}
return st;
}
struct Hash {
const static int H = 1e4 + 7, N = 5e6 + 7;
int n, nxt[N], head[H];
int st[N], w[N], d[N];
void init() {
n = 0, memset(head, -1, sizeof(head));
}
void ins(int _st, int _w, int _d) {
int p = _st % H;
for (int i = head[p]; ~i; i = nxt[i])
if (st[i] == _st) {
if (_w < w[i]) {
w[i] = _w, d[i] = _d;
} else if (_w == w[i]) {
inc(d[i], _d);
}
return ;
}
st[n] = _st, w[n] = _w, d[n] = _d;
nxt[n] = head[p], head[p] = n++;
}
void out() {
for (int p = 0; p < H; ++p)
for (int i = head[p]; ~i; i = nxt[i]) {
decode(cod, S, st[i]);
rep(j, 0, S + 1)
printf("%d", cod[j]);
printf("(%d) %d %d\n", st[i], w[i], d[i]);
}
}
} hs[2];
int n, m, v[807][8], h[807][8];
void blank(int x, int y, int t) {
rep(i, 0, hs[t].n) {
decode(cod, S, hs[t].st[i]);
int U = cod[y], flag = 0;
if (x == 0)
flag = 1;
else if (U > 0) {
rep(j, 0, m)
if (j != y && cod[j] == U) {
flag = 1;
break;
}
}
if (x > 0 && U > 0) {
hs[t ^ 1].ins(hs[t].st[i], hs[t].w[i] + v[x][y],
2ll * hs[t].d[i] % MOD);
}
if (y > 0 && flag) {
decode(cod, S, hs[t].st[i]);
cod[y] = cod[y - 1];
hs[t ^ 1].ins(encode(cod, S), hs[t].w[i] + h[x][y],
2ll * hs[t].d[i] % MOD);
}
if (flag) {
decode(cod, S, hs[t].st[i]);
cod[y] = 14;
hs[t ^ 1].ins(encode(cod, S), hs[t].w[i], hs[t].d[i]);
}
if (x > 0 && y > 0 && cod[y - 1] != U) {
decode(cod, S, hs[t].st[i]);
int L = cod[y - 1];
rep(j, 0, m)
if (cod[j] == U)
cod[j] = L;
hs[t ^ 1].ins(encode(cod, S), hs[t].w[i] + v[x][y] + h[x][y],
3ll * hs[t].d[i] % MOD);
}
}
}
int main() {
int T;
scanf("%d", &T);
rep(cas, 0, T) {
scanf("%d%d", &n, &m), S = m - 1;
rep(i, 0, n)
rep(j, 1, m)
scanf("%d", &h[i][j]);
rep(i, 1, n)
rep(j, 0, m)
scanf("%d", &v[i][j]);
int t = 0;
hs[t].init();
hs[t].ins(0, 0, 1);
rep(i, 0, n)
rep(j, 0, m) {
t ^= 1;
hs[t].init();
blank(i, j, t ^ 1);
}
fill_n(cod, m, 1);
int st = encode(cod, S);
int mst = -1, deg = -1;
rep(i, 0, hs[t].n)
if (hs[t].st[i] == st)
mst = hs[t].w[i], deg = hs[t].d[i];
printf("Case #%d: %d %d\n", cas + 1, mst, deg);
}
return 0;
}
HDU 5513 Efficient Tree的更多相关文章
- HDU - 5513 Efficient Tree(轮廓线DP)
前言 最近学了基于连通性的状压DP,也就是插头DP,写了几道题,发现这DP实质上就是状压+分类讨论,轮廓线什么的也特别的神奇.下面这题把我WA到死- HDU-5531 Efficient Tree 给 ...
- HDU 4925 Apple Tree(推理)
HDU 4925 Apple Tree 题目链接 题意:给一个m*n矩阵种树,每一个位置能够选择种树或者施肥,假设种上去的位置就不能施肥,假设施肥则能让周围果树产量乘2.问最大收益 思路:推理得到肯定 ...
- HDU 4871 Shortest-path tree 最短路 + 树分治
题意: 输入一个带权的无向连通图 定义以顶点\(u\)为根的最短路生成树为: 树上任何点\(v\)到\(u\)的距离都是原图最短的,如果有多条最短路,取字典序最小的那条. 然后询问生成树上恰好包含\( ...
- Hdu 5379 Mahjong tree (dfs + 组合数)
题目链接: Hdu 5379 Mahjong tree 题目描述: 给出一个有n个节点的树,以节点1为根节点.问在满足兄弟节点连续 以及 子树包含节点连续 的条件下,有多少种编号方案给树上的n个点编号 ...
- HDU 6035 - Colorful Tree | 2017 Multi-University Training Contest 1
/* HDU 6035 - Colorful Tree [ DFS,分块 ] 题意: n个节点的树,每个节点有一种颜色(1~n),一条路径的权值是这条路上不同的颜色的数量,问所有路径(n*(n-1)/ ...
- HDU 3333 - Turing Tree (树状数组+离线处理+哈希+贪心)
题意:给一个数组,每次查询输出区间内不重复数字的和. 这是3xian教主的题. 用前缀和的思想可以轻易求得区间的和,但是对于重复数字这点很难处理.在线很难下手,考虑离线处理. 将所有查询区间从右端点由 ...
- HDU 5573 Binary Tree 构造
Binary Tree 题目连接: http://acm.hdu.edu.cn/showproblem.php?pid=5573 Description The Old Frog King lives ...
- hdu 4786 Fibonacci Tree (2013ACMICPC 成都站 F)
http://acm.hdu.edu.cn/showproblem.php?pid=4786 Fibonacci Tree Time Limit: 4000/2000 MS (Java/Others) ...
- hdu 5534 Partial Tree 背包DP
Partial Tree Time Limit: 20 Sec Memory Limit: 256 MB 题目连接 http://acm.hdu.edu.cn/showproblem.php?pid= ...
随机推荐
- [转]Android系统Surface机制的SurfaceFlinger服务简要介绍和学习计划
转自:Android系统Surface机制的SurfaceFlinger服务简要介绍和学习计划 前面我们从Android应用程序与SurfaceFlinger服务的关系出发,从侧面简单学习了Surfa ...
- LINQ基础(一)
一.学习LINQ需要先了解以下知识点: 1.1 委托 1.2 匿名方法 1.3 Lambda表达式 1.4 扩展方法 二.LINQ原理: from s in names where s.le ...
- Apparmor——Linux内核中的强制访问控制系统
AppArmor 因为最近在研究OJ(oline judge)后台的安全模块的实现,所以一直在研究Linux下沙箱的东西,同时发现了Apparmor可以提供访问控制. AppArmor(Appli ...
- Node.js的简介和安装
一.Node.js的简介和安装 a) 什么是Node.js? Node.js是一个开发平台 让JavaScript运行在服务器端的开发平台 ---简单点说就是用JavaScript写服务器 ...
- BZOJ 1486 最小圈
二分答案是显然的,我们需要dfs版spfa判一下负环. 看起来是n^2其实很快. #include<iostream> #include<cstdio> #include< ...
- PHP_ArrayList
<?php //遍历数组的2种方式 $arr=array( "1"=>"hello", "2"=>"my&q ...
- 有意义的命名 Meaningful names
名副其实 use intention-revealing names 变量.函数或类的名称应该已经答复了所有的大问题.它该告诉你,他为什么会存在,他做什么事,应该怎么用.我们应该选择都是致命了计量对象 ...
- GridView按钮事件
1.html代码 <asp:TemplateField HeaderText="操作"> <ItemTemplate> <div style=&quo ...
- this的指向及应用
this的指向: //this 指的是调用 当前方法 (函数) 的那个对象 function fn1(){ this; } //fn1(); this => window //obj.oncli ...
- WCF之多个终结点
1.服务端配置如下(一个Service节点下可有多个endpoint,): <system.serviceModel> <services> <service name= ...