第十二届北京师范大学程序设计竞赛决赛 F.小组论【状压Dp】
来源:互联网 发布:淘宝法院拍卖流程 编辑:程序博客网 时间:2024/05/20 12:21
F. 小组论
Liserious最近迷上了密室逃脱,他总是在跪求他的小伙伴和他一起去玩各种各样的密室逃脱。
有一天他们遇到了一家非常复杂的密逃,为了获得其中一个关键道具,他们需要先站成一列,李希尔瑞斯的小伙伴们来自N个小组(比如一姐带领的“EEEat”;芳姐带领的“Doctooor”小组;51isoft带领的“Weeaaak”小组;力儿妹妹带领的“Mahhhjong”小组;龚犇带领的“Life Winnerrr”小组)。
现在每个人对自己的位置都有一个要求,要么他是他所在小组的队列里的第一个,要么他与他同一小组的前一个人的距离恰好为K。
Input
输入以EOF结束。
每组数据的第一行为一个整数N,表示小组的数量。
接下来N行,每行第一个整数M(M <= 5),表示这个小组的人数,接下来M个数,分别表示这M个人要求距离前一个同组的小伙伴的距离。
输入保证小伙伴的总数不超过20。
Output
对于每组数据,输出一个整数,表示总的排列的方案数。
Sample Input
21 12 1 2
Sample Output
3
思路:
这个题和这道题基本是一个套路:http://blog.csdn.net/mengxiang000000/article/details/60767512
我们知道,当n大的时候,M平均起来肯定小,也就是说对于每组的人的摆放的情况就会少很多,所以我们每次考虑两个组的合并。
设定Dp【i】表示已经排列出来状态为i的情况的方案数。
那么有:Dp【i】+=preDp【j】,这里i=j|X,这里X表示的是当前组成员的某种插入队列的方式。我们知道,当n大的时候,M平均起来肯定小,所以前期的情况数肯定灰常少,
所以我们只要注意常数就可以了。理论上是可以找到峰值操作次数的。
那么我们每一次将之前的排放方式和当前组的排放方式去合并Dp即可,注意常数。
Ac代码:
#include<stdio.h>#include<string.h>#include<iostream>#include<algorithm>#include<queue>#include<vector>#include<map>using namespace std;#define ll long long intint tot,n;int Dist[25][25];int num[25];int p[25];ll dp[(1<<21)];ll predp[(1<<21)];vector<int>mp[25];void Slove(){ vector<int>pre,zhongjie; memset(dp,0,sizeof(dp)); memset(predp,0,sizeof(predp)); pre.push_back(0);predp[0]=1; for(int i=1;i<=n;i++) { for(int j=0;j<mp[i].size();j++) { int tmpi=mp[i][j]; for(int k=0;k<pre.size();k++) { int tmppre=pre[k]; if((tmppre&tmpi)>0)continue; if(dp[tmppre+tmpi]==0)zhongjie.push_back(tmppre+tmpi); dp[tmppre+tmpi]+=predp[tmppre]; } } pre.clear(); for(int j=0;j<zhongjie.size();j++) { predp[zhongjie[j]]+=dp[zhongjie[j]]; dp[zhongjie[j]]=0; pre.push_back(zhongjie[j]); } zhongjie.clear(); } printf("%lld\n",predp[(1<<tot)-1]);}int main(){ while(~scanf("%d",&n)) { tot=0; for(int i=1;i<=24;i++)mp[i].clear(); for(int i=1;i<=n;i++) { int ki,cnt=1; scanf("%d",&ki); tot+=ki; num[i]=ki; for(int j=1;j<=ki;j++)scanf("%d",&Dist[i][j]); } for(int i=1;i<=n;i++) { int cnt=1; for(int j=1;j<=num[i];j++)p[j]=j,cnt*=j; while(cnt--) { next_permutation(p+1,p+1+num[i]); for(int pos=tot-1;pos>=0;pos--) { int tmp=0; int tmppos=pos; for(int j=1;j<=num[i];j++) { if(j>1)tmppos-=Dist[i][p[j-1]]; tmp+=(1<<tmppos); } if(tmppos<0)continue; mp[i].push_back(tmp); } } } Slove(); }}
- 第十二届北京师范大学程序设计竞赛决赛 F.小组论【状压Dp】
- 第十二届北京师范大学程序设计竞赛决赛训练总结【7/10】
- 北京师范大学第十二届程序设计竞赛
- 第十二届北京师范大学程序设计竞赛决赛 C. 方(芳)格(哥)取数【思维】
- 第十二届北京师范大学程序设计竞赛 H. 汉诺塔
- 杨辉三角形//第八届北京师范大学程序设计竞赛决赛
- 【BNUOJ】【第十四届北京师范大学程序设计竞赛决赛】D. Air Hockey
- 第十五届北京师范大学程序设计竞赛决赛(网络同步赛)
- 第十五届北京师范大学程序设计竞赛决赛(网络同步赛)
- 第十五届北京师范大学程序设计竞赛决赛 A.Another Server【思维】
- 第十五届北京师范大学程序设计竞赛决赛 D. Disdain Chain【思维】
- 第十五届北京师范大学程序设计竞赛决赛(网络同步赛)
- 第十五届北京师范大学程序设计竞赛决赛 D. Disdain Chain
- 第十五届北京师范大学程序设计竞赛决赛(网络同步赛)
- 第十三届北京师范大学程序设计竞赛决赛 【(6+2)/10】
- 北京师范大学第十四届ACM决赛- F Training Plan dp
- 第十二届北京师范大学程序设计竞赛网络预赛 2014-04-19
- 第十二届北京师范大学程序设计竞赛 A Liserious战队
- 1308: 最遥远的距离 [最短路]
- 立个flag
- c++ 技巧
- 分类(category)是门学问
- github using
- 第十二届北京师范大学程序设计竞赛决赛 F.小组论【状压Dp】
- JDBC预编译语句表名占位异常
- JS基础--数组
- 8.6
- 对抗样本与生成式对抗网络
- HDU 6060 RXD and dividing(树形DP+贪心)
- 初级设计程序的小套路
- CentOS6.5与Windows10共享root用户文件夹
- IO流——模拟定义BufferedReader