UVA 10531 Maze Statistics 迷宫统计 迷宫插头DP 四联通 概率
题意:
有一个N*M的图,每个格子有独立概率p变成障碍物。你要从迷宫左上角走到迷宫右下角。求每个格子成为一个有解迷宫中的障碍物的概率。N <= 5,M <= 6
分析:
这真是一道好题,网上几乎没有任何关于四连通的插头DP的任何资料,这道题目很好地反映了这类问题。
四连通中,只要你存在了右插头,必然存在下插头,当然,你的插头不一定需要真正连到可行格子中,因此在当前行中你只需要记录右插头。
但是不是需要换行的吗?由于下插头跟右插头是同时存在的,那么我们只需要把右插头当做下插头来用就可以了,是不是比普通的简单路径的插头dp简单很多?
来,我们看一下转移吧,其实情况的分类还是跟普通的插头dp一样的,不得不说cdq的插头普适性真是厉害。
1、同时存在左插头和上插头,那么只需要把连通块连一下,然后记一个右插头。
2、只存在左插头或者上插头,那么只需要延续连通块,再记一个右插头。
3、都不存在左插头和上插头,那么只需要新建一个连通块,记在右插头。
而换行操作,只需要把右插头变成下插头就可以了。
程序:(学习了某岛大神的代码之后才写出来了这份代码)
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <string>
#include <algorithm>
#include <iostream> using namespace std; typedef long long LL;
const int HASH = ;
const int STATE = ;
const int MAXD = ;
const double EPS = 1e-;
int n, m;
double maze[MAXD][MAXD];
int code[MAXD], ch[MAXD]; int fcmp(double x)
{
return x < -EPS ? - : x > EPS;
} void decode(LL st)
{
int i;
for (i = m; i >= ; --i)
{
code[i] = st&;
st >>= ;
}
} LL encode()
{
LL st = ;
int i, cnt = ;
memset(ch, -, sizeof(ch));
ch[] = , ch[] = ;
for (i = ; i <= m; ++i)
{
if (ch[code[i]] == -)
ch[code[i]] = ++cnt;
code[i] = ch[code[i]];
st <<= ;
st |= code[i];
}
return st;
} struct HASHMAP
{
int head[HASH], next[STATE], size;
LL state[STATE];
double f[STATE];
void clear()
{
size = ;
memset(head, -, sizeof(head));
}
void push(LL st, double ans)
{
int i;
decode(st);
for (i = ; i <= m; ++i)
if (code[i] == )
break ;
if (i == m+) //如果编号为1的连通块不存在,那就不可行
return ;
int x = st%HASH;
for (i = head[x]; i != -; i = next[i])
if (st == state[i])
{
f[i] += ans;
return ;
}
f[size] = ans;
state[size] = st;
next[size] = head[x];
head[x] = size ++;
}
}hm[]; void in()
{
int i, j;
scanf("%d %d", &n, &m);
for (i = ; i <= n; ++i)
for (j = ; j <= m; ++j)
scanf("%lf", &maze[i][j]);
} void dp_blank(int i, int j, int cur)
{
if (!fcmp(1.0-maze[i][j]))
return ;
int k, lef, up, t;
for (k = ; k < hm[cur].size; ++k)
{
if (!fcmp(hm[cur].f[k]))
continue ;
decode(hm[cur].state[k]);
lef = code[j-], up = code[j];
if (lef && up)//分类讨论只对右插头做修改
{
if (lef != up)
{
if (lef < up)
swap(lef, up);
for (t = ; t <= m; ++t)
if (code[t] == lef)
code[t] = up;
}
}
else
{
if (lef || up)
code[j] = lef|up;
else
code[j] = m+;
}
hm[cur^].push(encode(), hm[cur].f[k]*(1.0-maze[i][j]));
}
} void dp_block(int i, int j, int cur)
{
if (!fcmp(maze[i][j]))
return ;
int k;
for (k = ; k < hm[cur].size; ++k)
{
if (!fcmp(hm[cur].f[k]))
continue ;
decode(hm[cur].state[k]);
code[j] = ;//同理
hm[cur^].push(encode(), hm[cur].f[k]*maze[i][j]);
}
} double solve()
{
int i, j, cur = ;
memset(code, , sizeof(code));
hm[cur].clear();
code[] = ;
hm[cur].push(encode(), );
for (i = ; i <= n; ++i)
for (j = ; j <= m; ++j)
{
hm[cur^].clear();
dp_blank(i, j, cur);
dp_block(i, j, cur);
cur ^= ;
}
double ret = ;
for (i = ; i < hm[cur].size; ++i)
{
decode(hm[cur].state[i]);
if (code[m] == )
ret += hm[cur].f[i];
}
return ret;
} void work()
{
int i, j;
double sum = solve();
for (i = ; i <= n; ++i)
for (j = ; j <= m; ++j)
{
double cache = maze[i][j];
maze[i][j] = 1.0;
printf("%.6lf%c", solve()*cache/sum, (j == m) ? '\n' : ' ');
maze[i][j] = cache;
}
} int main()
{
int T, iCase = ;
scanf("%d", &T);
while (T --)
{
if (iCase++)
printf("\n");
in();
work();
}
return ;
}
UVA 10531 Maze Statistics 迷宫统计 迷宫插头DP 四联通 概率的更多相关文章
- uva 11270 - Tiling Dominoes(插头dp)
题目链接:uva 11270 - Tiling Dominoes 题目大意:用1∗2木块将给出的n∗m大小的矩阵填满的方法总数. 解题思路:插头dp的裸题,dp[i][s]表示第i块位置.而且该位置相 ...
- BZOJ_3365_[Usaco2004 Feb]Distance Statistics 路程统计&&POJ_1741_Tree_点分治
BZOJ_3365_[Usaco2004 Feb]Distance Statistics 路程统计&&POJ_1741_Tree_点分治 Description 在得知了自己农 ...
- 动态规划之插头DP入门
基于联通性的状态压缩动态规划是一类非常典型的状态压缩动态规划问题,由于其压缩的本质并不像是普通的状态压缩动态规划那样用0或者1来表示未使用.使用两种状态,而是使用数字来表示类似插头的状态,因此.它又被 ...
- 插头dp
插头dp 感受: 我觉得重点是理解,算法并不是直接想出怎样由一种方案变成另一种方案.而是方案本来就在那里,我们只是枚举状态统计了答案. 看看cdq的讲义什么的,一开始可能觉得状态很多,但其实灰常简单 ...
- HDU 4113 Construct the Great Wall(插头dp)
好久没做插头dp的样子,一开始以为这题是插头,状压,插头,状压,插头,状压,插头,状压,无限对又错. 昨天看到的这题. 百度之后发现没有人发题解,hust也没,hdu也没discuss...在acm- ...
- HDU 4949 Light(插头dp、位运算)
比赛的时候没看题,赛后看题觉得比赛看到应该可以敲的,敲了之后发现还真就会卡题.. 因为写完之后,无限TLE... 直到后来用位运算代替了我插头dp常用的decode.encode.shift三个函数以 ...
- 插头DP专题
建议入门的人先看cd琦的<基于连通性状态压缩的动态规划问题>.事半功倍. 插头DP其实是比较久以前听说的一个东西,当初是水了几道水题,最近打算温习一下,顺便看下能否入门之类. 插头DP建议 ...
- HDU 1693 Eat the Trees(插头DP、棋盘哈密顿回路数)+ URAL 1519 Formula 1(插头DP、棋盘哈密顿单回路数)
插头DP基础题的样子...输入N,M<=11,以及N*M的01矩阵,0(1)表示有(无)障碍物.输出哈密顿回路(可以多回路)方案数... 看了个ppt,画了下图...感觉还是挺有效的... 参考 ...
- 插头dp的几个模板
/* ural1519 求经过全部可行点的哈密顿回路的个数 括号匹配法,转移有点复杂,可是时间空间比較小 */ #include<cstdio> #include<cstring&g ...
随机推荐
- js-打地鼠游戏开发
[生成画布] 第1课[随机生成地鼠] 第2课[定时生成地鼠] 第3课[打地鼠完结篇] 第4课 优酷在线播放地址 http://list.youku.com/albumlist/show?id=2939 ...
- 用C#实现通过串口对设备的数据采集--Server层
今天中午没睡午觉,头昏眼花的,实在写不了代码,把这几天写的Server层数据采集的程序整理了一下. WatrLevelDataCollectServer.cs using System; using ...
- linux 内核信号量
Linux内核的信号量在概念和原理上和用户态的System V的IPC机制信号量是相同的,不过他绝不可能在内核之外使用,因此他和System V的IPC机制信号量毫不相干. 信号量在创建时需要设置一个 ...
- [node.js] async/await如何优雅处理异常?
node.js的世界,从callback开始,不会止于async. 所有人都在骂为什么不能完全进化,其实我感觉这就是老外的细心,为了承上.这也就是为什么async其实就是promise一样,假如不是一 ...
- AD服务器安装文档
Windows Server 2008 R2 AD服务器搭建 1. AD服务器简介 应用到: Windows Server 2003, Windows Server 2003 R2, Windows ...
- oracle只要第一条数据SQL
select * from ( select * from COMMON_BIZREL_WF where sponsor is not null order by serialid ) where r ...
- python RSA加密解密及模拟登录cnblog
1.公开密钥加密 又称非对称加密,需要一对密钥,一个是私人密钥,另一个则是公开密钥.公钥加密的只能私钥解密,用于加密客户上传数据.私钥加密的数据,公钥可以解密,主要用于数字签名.详细介绍可参见维基百科 ...
- google浏览器中,使用clockwork 来调试
参考:https://laravel-china.org/courses/laravel-package/1976/debugging-tool-under-chrome-itsgoingdclock ...
- linux nginx php-fpm被攻击
1.nginx错误日志:报错 2018/05/30 16:30:55 [error] 8765#0: *1485 connect() to unix:/tmp/php-70-cgi.sock fail ...
- set -o vi AIX下shell
set -o vi 再用esc+K键就可以使用上一条指令了 esc+kesc+j上下翻 ksh默认是emacs风格的.set -o emacs 在AIX下使用自己已经使用过的命令 在AIX下使用,默认 ...