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= ...
随机推荐
- Java与.NET DES加密解密互转
上代码: Java代码: import javax.crypto.Cipher; import javax.crypto.SecretKey; import javax.crypto.SecretKe ...
- 使用OCI向Oracle插入Geometry数据
使用C/C++操作Oracle数据库,使用OCI可谓是最强大,当然也是最难的方式.Oracle是一个功能复杂而强大的数据库,它可以很好的支持空间数据(Oracle spatial).如何使用OCI向O ...
- hdu 2044
ps:好吧,WA了两次,第一次注意到要用long long了...但是printf那里给忘了...又WA.. 代码:#include "stdio.h"long long dp[5 ...
- 12-27 UITableView常用属性及方法
UITableView也有自己的代理协议,它本身继承自UIScrollView 一:代理要遵守代理协议<UITableViewDelegate>,代理协议中的代理方法: 1.改变某一行的行 ...
- struts2和servlet同时用(访问servlet时被struts2过滤器拦截问题的解决)
在同一个项目中间,如果既用到servlet有用了struts2的框架,运行项目时可能无法正常使用servlet,原因是在配置struts2的核心控制器时<url-pattern>/*< ...
- Android中Preference的使用以及监听事件分析
在Android系统源码中,绝大多数应用程序的UI布局采用了Preference的布局结构,而不是我们平时在模拟器中构建应用程序时使用的View布局结构,例如,Setting模块中布局.当然,凡事都有 ...
- 企业级的App发布流程
1.先注册企业级开发证书http://blog.sina.com.cn/s/blog_6cad9db90102uy0s.html2.开发 企业流程http://blog.csdn.net/pang04 ...
- POJ2449 (k短路)
#include <cstdio> #include <cstring> #include <cmath> #include <algorithm> # ...
- 《More Effective C++ 》笔记
条款10 防止构造函数里的资源泄露 条款20 协助编译器实现返回值优化 条款22 考虑使用op=来取代单独的op运算符 条款26 限制类对象的个数 条款27 要求或禁止对象分配在堆上
- 有趣的数-回文数(Palindrome number)
文章转自http://blog.163.com/hljmdjlln@126/blog/static/5473620620120412525181/ 做LC上的题"Palindrome num ...