AtCoder Contest199 E - Permutation(状压dp)
发布日期:2021-06-30 10:33:54 浏览次数:2 分类:技术文章

本文共 1062 字,大约阅读时间需要 3 分钟。

题意

[ 1 , n ] [1,n] [1,n]的满足一下条件的排列方案数

对于 m m m个限制,满足

a 1 , a 2 . . . a x i a_1,a_2...a_{x_i} a1,a2...axi中至多有 z i z_i zi个数小于等于 y i y_i yi

n < = 18 , m < = 100 n<=18,m<=100 n<=18,m<=100


比较裸的状压 D P \rm DP DP

定义 f [ i ] f[i] f[i]表示填数状态为 i i i时的合法方案数,第 j j j位二进制为 1 1 1表示数字 j j j已经被填过

比如 i i i中有 x x x 1 1 1,说明已经填充了 k k k个数

那么每次 O ( n ) O(n) O(n)枚举第 k + 1 k+1 k+1个位置填哪个数,并检查是否满足 x i = k + 1 x_i=k+1 xi=k+1的那些限制

这样每次转移,都考虑了可能的限制

总体复杂度为 O ( 2 n ∗ n ) O(2^n*n) O(2nn),略带常数(因为有时候需要考虑 m m m个限制)

#include 
using namespace std;long long f[1<<18];int n,m,pre[22];typedef pair
p;vector

vec[22];int main(){

cin >> n >> m; for(int i=1;i<=m;i++) {
int x,y,z; scanf("%d%d%d",&x,&y,&z); vec[x].push_back( p(y,z) ); } f[0] = 1; for(int i=0;i<(1<
>(j-1))&1 ); for(int j=1;j<=n;j++) pre[j] += pre[j-1]; for(int j=1;j<=n;j++) {
if( (i>>(j-1))&1 ) continue; //在这个位置放置j int flag = 1; for(auto v:vec[pre[n]+1] ) if( pre[v.first]+( j<=v.first )>v.second ) flag = 0; if( flag ) f[i|(1<<(j-1))] += f[i]; } } cout << f[(1<

转载地址:https://issue-is-vegetable.blog.csdn.net/article/details/117534549 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!

上一篇:GBN(后退n帧协议)与SR(选择性重传协议)
下一篇:1523 E - Crypto Lights(期望+组合数学思维)

发表评论

最新留言

能坚持,总会有不一样的收获!
[***.219.124.196]2024年04月12日 08时47分21秒

关于作者

    喝酒易醉,品茶养心,人生如梦,品茶悟道,何以解忧?唯有杜康!
-- 愿君每日到此一游!

推荐文章