集合划分状压dp
给一个 $n$ 个点 $m$ 条边的无向图,每条边有 $p_i$ 的概率消失,求图连通的概率
$n \leq 9$
sol:
我们考虑一个 $dp$
$f_{(i,S)}$ 表示只考虑前 $i$ 条边,当前图连通的状态为 $S$ 的概率
设这条边没有消失,图的新连通状态为 $T$
那转移到 $T$ 的概率就是 $(1 - p_i)$
不变的概率是 $p_i$
然后一个滚动数组就做完了
然后我们考虑,怎么把“图的连通状态”这个东西状压出来
一个 idea 是,我们可以在状态里记录每个点所处的连通块里最小的点的编号,比如 123 是一个连通块,45 是一个连通块,我们这个状态就是 12344
这样的话,因为每个点所处连通块里最小的点的编号不超过它的编号,状态数是 $O(n!)$ 的,但如果我们直接存一个 9 位数,数组显然开不下
1.我们可以哈希一下,把代码写成这样
int h;
map<vector<int>,int> hsh;
map<int,vector<int> > reh;
inline int gethsh(vector<int> v)
{
if(!hsh[v])
{
hsh[v] = ++h;
reh[h] = v;
}
return hsh[v];
}
inline vector<int> getreh(int h){return reh[h];}
2.或者我们可以动动脑子
显然,这个状态的最后一位数只有 $n$ 种情况
然后,倒数第二位只有 $n - 1$ 种情况(不能比最后一位大)
然后,倒数第三位只有 $n - 2$ 种情况
...
然后,最高位只有 $1$ 种情况($1$ 只能属于 $1$)
于是我们把最后一位数乘以 $n$ ,倒数第二位乘以 $(n-1) \times n$ ,倒数第三位乘以 $(n-2) \times (n-1) \times n$ ... 最高位乘以 $n!$
就把状态压到了 $O(n!)$ 个数里
如果想知道一个值对应的状态是什么,从高到低除再取余一下就可以了
于是可以 dp 了
学习了 yyc 同学的写法,预处理出了前 n 位所有状态
$state_(i,j)$ 表示第 $i$ 个方案的第 $j$ 位是什么,也就是 $j$ 点在第 $i$ 种状态里所属的连通块的编号最小的点
frustrated好强呀
%%%
#include<bits/stdc++.h>
#define LL long long
using namespace std;
inline int read()
{
int x = ,f = ;char ch = getchar();
for(;!isdigit(ch);ch = getchar())if(ch == '-')f = -f;
for(;isdigit(ch);ch = getchar())x = * x + ch - '';
return x * f;
}
int n,m;
double grid[][];
namespace p30
{
int fa[];inline int find(int x){return x == fa[x] ? x : fa[x] = find(fa[x]);}
struct EDG{int u,v;double p;}es[];
int _main()
{
for(int i=;i<=m;i++)
{
int a = read(),b = read();double p;
scanf("%lf",&p);
//grid[a][b] = grid[b][a] = (1.00 - p);
es[i] = (EDG){a,b,1.00 - p};
}
int MAXSTATE = ( << m) - ;
double zgl = 0.0;
for(int S=;S<=MAXSTATE;S++)
{
double curgl = 1.00;
for(int i=;i<=n;i++)fa[i] = i;
for(int i=;i<=m;i++)
{
if(S & ( << (i - )))
{
int fu = find(es[i].u),fv = find(es[i].v);
curgl *= es[i].p;if(fu == fv)continue;
fa[fu] = fv;
}
else curgl *= (1.00 - es[i].p);
}
int flg = ;
for(int i=;i<=n;i++)if(find(i) != find())flg = ;
if(flg)zgl += curgl;
}printf("%.3f\n",zgl);
return ;
}
}
namespace prng
{
int _main()
{
srand(time());
int RNG = rand() % + ;
double rng = RNG / 1000.0;
printf("%.3f\n",rng);
return ;
}
}
namespace p100
{
const int maxn = ;
int fac[],u[],v[],state[maxn][],t[];
double w[],f[maxn],g[maxn];
inline int calc()
{
int res = ;
for(int i=;i<=n;i++) res += (t[i] - ) * (fac[n] / fac[i]);
return res + ;
}
int _main()
{
for(int i=;i<=m;i++)
{
u[i] = read(),v[i] = read();
scanf("%lf",&w[i]);
}fac[] = ;
for(int i=;i<=;i++)fac[i] = fac[i - ] * i;
for(int i=;i<=n;i++)state[][i] = ;
for(int i=;i<=fac[n];i++)
{
int x = n;
while()
{
state[i][x] = state[i - ][x] + ;
if(state[i][x] > x)state[i][x] = ,state[i][x - ]++;
else break;
x--;
}
for(int j=;j<x;j++)state[i][j] = state[i - ][j];
}
f[fac[n]] = 1.0;
for(int i=;i<=m;i++)
{
for(int j=;j<=fac[n];j++)
{
if(f[j])
{
for(int kk=;kk<=n;kk++)t[kk] = state[j][kk];
for(int kk=;kk<=n;kk++)
if(state[j][v[i]] == t[kk] || t[kk] == state[j][u[i]]) t[kk] = min(state[j][u[i]],state[j][v[i]]);
g[calc()] += f[j] * ( - w[i]);
g[j] += f[j] * w[i];
}
}
for(int j=;j<=fac[n];j++)f[j] = g[j],g[j] = ;
}
printf("%.3f",f[]);
}
}
int main()
{
//freopen("10.in","r",stdin);
//freopen("10.out","w",stdout);
n = read(),m = read();
//if(n <= 8 || m <= 23)p30::_main();
//else prng::_main();
p100::_main();
}
集合划分状压dp的更多相关文章
- bzoj 2734 集合悬殊 (状压dp)
大意: 给定$n$, 求集合{1,2,...n}的子集数, 满足若$x$在子集内, 则$2x,3x$不在子集内. 记$f(x)$为$x$除去所有因子2,3后的数, 那么对于所有$f$值相同的数可以划分 ...
- [WC2018]州区划分(状压DP+FWT/FMT)
很裸的子集反演模板题,套上一些莫名其妙的外衣. 先预处理每个集合是否合法,再作显然的状压DP.然后发现可以写成子集反演的形式,直接套模板即可. 子集反演可以看这里. 子集反演的过程就是多设一维代表集合 ...
- UOJ348 WC2018 州区划分 状压DP、欧拉回路、子集卷积
传送门 应该都会判欧拉回路吧(雾 考虑状压DP:设\(W_i\)表示集合\(i\)的点的权值和,\(route_i\)表示点集\(i\)的导出子图中是否存在欧拉回路,\(f_i\)表示前若干个城市包含 ...
- UOJ #348 州区划分 —— 状压DP+子集卷积
题目:http://uoj.ac/problem/348 一开始可以 3^n 子集DP,枚举一种状态的最后一个集合是什么来转移: 设 \( f[s] \) 表示 \( s \) 集合内的点都划分好了, ...
- 【UOJ348】【WC2018】州区划分 状压DP FWT
题目大意 给定一个\(n\)个点的无向图,对于每种 \(n\) 个点的划分\(\{S_1,S_2,\ldots,S_k\}\),定义它是合法的,当且仅当每个点都在其中的一个集合中且对于任何的\(i\i ...
- Luogu4221 WC2018州区划分(状压dp+FWT)
合法条件为所有划分出的子图均不存在欧拉回路或不连通,也即至少存在一个度数为奇数的点或不连通.显然可以对每个点集预处理是否合法,然后就不用管这个奇怪的条件了. 考虑状压dp.设f[S]为S集合所有划分方 ...
- BZOJ_2734_[HNOI2012]集合选数_构造+状压DP
BZOJ_2734_[HNOI2012]集合选数_构造+状压DP 题意:<集合论与图论>这门课程有一道作业题,要求同学们求出{1, 2, 3, 4, 5}的所有满足以 下条件的子集:若 x ...
- [HNOI2012]集合选数(状压DP+构造)
题目要求若出现x,则不能出现2x,3x 所以我们考虑构造一个矩阵 \(1\ 2\ 4 \ 8--\) \(3\ 6\ 12\ 24--\) \(9\ 18\ 36--\) \(--\) 不难发现,对于 ...
- B - 集合选数 (状压DP)
题目链接:https://cn.vjudge.net/contest/281960#problem/B 题目大意:中文题目 具体思路: 我们通过构造矩阵, x , 3x,9x,27x 2x,6x,18 ...
随机推荐
- 写出完美的snprintf
平时公司的代码安全扫描会给出不安全代码的告警,其中会检查代码中间的strcpy和sprintf函数,而要求使用strncpy和snprintf.今天我们讨论一下怎样写出完美的snprintf. snp ...
- iOS流布局UICollectionView系列七——三维中的球型布局
摘要: 类似标签云的球状布局,也类似与魔方的3D布局 iOS流布局UICollectionView系列七——三维中的球型布局 一.引言 通过6篇的博客,从平面上最简单的规则摆放的布局,到不规则的瀑 ...
- (总结)RHEL/CentOS 7.x的几点新改变
一.CentOS的Services使用了systemd来代替sysvinit管理 1.systemd的服务管理程序: systemctl是主要的工具,它融合之前service和chkconfig的功能 ...
- memcache 的使用
基础知识 memcached 是一个开源项目,旨在利用多个服务器内的多余 RAM 来充当一个可存放经常被访问信息的内存缓存.这里的关键是使用了术语缓存:memcached 为加载自他处的信息提供的是内 ...
- Java使用jmagick处理图片遇到的异常
java通过ImageMagick处理图片遇到问题: 下面异常都是我一个一个遇到的: 异常1: Exception in thread "main" java.lang.Unsat ...
- poj2349
Arctic Network Time Limit: 2000MS Memory Limit: 65536K Total Submissions: 0 Accepted: 0 Descript ...
- docker笔记一
docker概念介绍: docker 是一个装在linux上的普通的软件.利用docker的命令,可以创建一个带有linux操作系统的镜像文件,docker命令运行这个带的linux操作系的镜像文件, ...
- 异常:The JSP specification requires that an attribute name is preceded by whitespace
The JSP specification requires that an attribute name is preceded by whitespace: 其实这句话翻译就是 属性后面要必须有空 ...
- JVM性能优化, Part 1 ―― JVM简介
JVM性能优化这些列文章共分为5章,是ImportNew上面翻译自Javaworld: 第1章:JVM技术概览 第2章:编译器 第3章:垃圾回收 第4章:并发垃圾回收 第5章:可伸缩性 众所周知,Ja ...
- iOS NSDateFormatter 不安全线程 处理
记得 上次我们开CodeReView大会 有人提出 " NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init]; ...