WC2008观光游览【BZOJ2595】【斯坦纳树】
来源:互联网 发布:大专学软件开发 编辑:程序博客网 时间:2024/04/28 07:06
WC2008观光游览【BZOJ2595】【斯坦纳树】
神奇的解法
题目传送点
想了解斯坦纳树的戳这
其实这种表格的题目还可以写插头DP(•‾̑⌣‾̑•)✧˖°
(不会= =|||)
我们忽略刚刚的话题,说说这个斯坦纳树。
《斯坦纳树问题及其推广》说道:
斯坦纳树问题属于NP困难问题,因此看来不可能出现有效算法,即所谓的多项式算法来处理这一问题。目前文献中所提出的算法只不过是遍数法的种种改进,即在具体计算过程中,根据给定的实际问题,利用某些准则可以抛弃一部分情况不予考虑
也就是说,大部分的斯坦纳树问题都是构造的,没有一个特定的解法,我们学长还和我们抱怨说:考一些莫名其妙的题┑( ̄▽  ̄)┍
(闲话不多说,题解上)
题解
[纯暴力]
太暴力了这种办法,枚举每一个不是风景的格子按不安排志愿者
[YY]
用
[插头DP]
不会。。。。
[斯坦纳树]
这个才是重点。
我们依然定义一个状态
f[i][j][s]=f[i][j][s′]+f[i][j][s−s′]−val(i,j)(s′⊊s) (两棵树的合并,会有一个点算重了,要减掉,枚举s′ 的时候,s′ 不能为∅ ,也不能等于s )f[i][j][s′]=min(f[x][y][s]+val(i,j)) ((i,j) 从周围四个点转移过来,当然,如果(i,j) 是个景点,那么,s′ 要比s 多一个点)
预处理:
首先
[代码]
(大家帮我向
#include <iostream>#include <cstdlib>#include <cstdio>#include <queue>#include <cstring>using namespace std;const int maxn = 13, maxm = 1035, INF = 0x7fffffff / 3, bai = 102501, shi = 1024;const int dirx[] = {0, 0, 1, -1}, diry[] = {1, -1, 0, 0};int n, m, k, M, map[maxn][maxn], f[maxn][maxn][maxm], fa[maxn][maxn][maxm], ord[maxn][maxn];bool used[1200130], ans[maxn][maxn];queue<int>Q;int calc(int x, int y, int s) {return x * bai + y * shi + s;}bool isSubet(int a, int b) {return (a | b) == a;}void spfa(int sta) { while(!Q.empty()) { int u = Q.front(); Q.pop(); int x = u / bai, y = u % bai / shi; for(int d = 0; d < 4; d++) { int nx = x + dirx[d], ny = y + diry[d]; if(nx < 1 || ny < 1 || nx > n || ny > m) continue; int ns = sta | ord[nx][ny]; if(f[nx][ny][ns] > f[x][y][sta] + map[nx][ny]) { f[nx][ny][ns] = f[x][y][sta] + map[nx][ny]; fa[nx][ny][ns] = u; int k = calc(nx, ny, ns); if(!used[k] && sta == ns) {used[k] = true; Q.push(k);} } } used[u] = false; }}void initForOut(int x, int y, int sta) { ans[x][y] = true; int k = fa[x][y][sta]; if(!k) return; int i = k / bai, j = k % bai / shi, s = k % bai % shi; initForOut(i, j, s); if(i == x && j == y) initForOut(i, j, sta - s);}void out() { for(int i = 1; i <= n; i++) { for(int j = 1; j <= m; j++) if(ans[i][j]) if(map[i][j]) putchar('o'); else putchar('x'); else putchar('_'); putchar('\n'); }}int main() { freopen("trip.in", "r", stdin); freopen("trip.out", "w", stdout); scanf("%d%d", &n, &m); for(int i = 1; i <= n; i++) for(int j = 1; j <= m; j++) for(int s = 0; s < 1024; s++) f[i][j][s] = INF; for(int i = 1; i <= n; i++) for(int j = 1; j <= m; j++) { scanf("%d", &map[i][j]); f[i][j][0] = map[i][j]; if(!map[i][j]) f[i][j][1 << (k++)] = 0, ord[i][j] = 1 << (k - 1); } M = 1 << k; for(int sta = 1; sta < M; sta++) { for(int i = 1; i <= n; i++) { for(int j = 1; j <= m; j++) { for(int s = 1; s < sta; s++) { if(isSubet(sta, s)) { if(f[i][j][sta] > f[i][j][s] + f[i][j][sta - s] - map[i][j]) { f[i][j][sta] = f[i][j][s] + f[i][j][sta - s] - map[i][j]; fa[i][j][sta] = calc(i, j, s); } } } if(f[i][j][sta] != INF) Q.push(calc(i, j, sta)), used[calc(i, j, sta)] = true; } } spfa(sta); } for(int i = 1; i <= n; i++) for(int j = 1; j <= m; j++) if(!map[i][j]) { printf("%d\n", f[i][j][M - 1]); initForOut(i, j, M - 1); out(); return 0; } return 0;}
- WC2008观光游览【BZOJ2595】【斯坦纳树】
- 【BZOJ2595】【Wc2008】游览计划、斯坦纳树
- 【bzoj2595】[Wc2008]游览计划 斯坦纳树
- [BZOJ2595][Wc2008]游览计划(斯坦纳树)
- Bzoj2595 游览计划 斯坦纳树
- WC2008 游览计划 斯坦纳树
- 2595: [Wc2008]游览计划 斯坦纳树
- 【BZOJ2595】 [Wc2008]游览计划
- [bzoj2595][WC2008]游览计划
- bzoj2595: [Wc2008]游览计划
- Bzoj2595: [Wc2008]游览计划
- 【WC2008】bzoj2595 游览计划
- bzoj2595 游览计划 斯坦纳树&状压Dp
- 【BZOJ】【P2595】【Wc2008】【游览计划】【题解】【斯坦纳树】
- BZOJ 2595 Wc2008 游览计划 斯坦纳树
- bzoj 2595: [Wc2008]游览计划(斯坦纳树)
- BZOJ 2595: [Wc2008]游览计划 斯坦纳树
- BZOJ 2595: [Wc2008]游览计划 斯坦纳树
- python3环境下的TCP协议与UDP协议的socket编程
- 8.对象初始化
- 【网络流之最小割模型】poj3469 BZOJ3144 UVA1212
- 【HDU】 2546 饭卡
- 对于CV&MV的思考
- WC2008观光游览【BZOJ2595】【斯坦纳树】
- Android基础之Intent
- 从今天开始啊,我要开始写博客啦!!
- ios8和ios7的主要区别
- bzoj2440: [中山市选2011]完全平方数
- 深入学习、理解select语句、delete语句以及其他SQL语句
- Oracle 通过存储过程给关联者发信
- 天池冠军比赛心得体会
- iptables基础说明