(Lineup the Dominoes筛子)三维状压
描述:\(一堆筛子,每个筛子两个面,上面有1-6之间的数字。后一个筛子与前一个筛子的接触面的点数必须相等。\)
\(求,有多少种方案堆完筛子。(方案只关心筛子的位置,不关心是否翻转)\)
\(dp[mask][last][orientation]\),表示使用\(mask\)指示的子数组,以第\(last\)个多米诺骨牌为结尾的合法排列的方法
\(orientation\)多米诺骨牌的状态,0表示原来的方向,1表示翻转。
如果\(mask\)使用二进制表示为01010101,表示使用第0,2,4,6个多米诺骨牌排列而成,1代表使用这个位置上的数组,0代表不使用。
那么,我们先枚举所有状态,再从状态中枚举两个被用过的筛子\(last\)和\(i\)
假设last是结尾用的筛子,那么尝试接到筛子\(i\)上去
如果i和last都是原来的方向:
\(dp[mask][last][0] =sum (dp[mask][last][0],dp[premask][i][0])。\)
如果i是翻转的,last是原来的方向:
\(dp[mask][last][0] =sum (dp[mask][last][0],dp[premask][i][1])。\)
如果i是原来的方向,last是翻转的方向:
\(dp[mask][last][1] =sum (dp[mask][last][1],dp[premask][i][0])。\)
如果i和last都是翻转的方向:
\(dp[mask][last][1] =sum (dp[mask][last][1],dp[premask][i][1])。\)
最后只要将所有\(dp[1<<n-1][i][0]\)和\(dp[1<<n-1][i][1]\)累加所得即可(当\(s[i]==t[i]\)时不用加\(dp[1<<n-1][i][1]\))。
特殊情况——如果所有的多米诺骨牌都是一样的,那么所有的顺序都是有效的,即全排列。
标程
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int mod=1e9+7;
int s[20],t[20];
ll p[25];
ll dp[70000][20][2];
int main()
{
int T,i,mask,last,n;
p[0]=1;
for(i=1;i<=20;i++)p[i]=p[i-1]*i%mod;
scanf("%d",&T);
while(T--)
{
int fl=0;
scanf("%d",&n);
for(i=0;i<n;i++)
scanf("%d%d",&s[i],&t[i]);
for(i=1;i<n;i++)
if((s[i]==s[0]&&t[i]==t[0])||(s[i]==t[0]&&t[i]==s[0])){}
else {fl=1;break;}
// 特殊情况——如果所有的多米诺骨牌都是一样的,那么所有的顺序都是有效的。
if(fl==0)
{
printf("%lld\n",p[n]);
continue;
}
memset(dp,0,sizeof dp);
//初始化,表示每个骨牌都有一个初始状态
for(i=0;i<n;i++)
dp[1<<i][i][0]=dp[1<<i][i][1]=1;
for(mask=3;mask<(1<<n);mask++)
{
for(last=0;last<n;last++)
{
if((mask&(1<<last))==0)continue;
int premask=mask-(1<<last);
for(i=0;i<n;i++)
{
if((premask&(1<<i))==0)continue;
//i和last都是原来的方向
if(t[i]==s[last])
dp[mask][last][0] = (dp[mask][last][0]+dp[premask][i][0])%mod;
//i是翻转的,last是原来的方向
else if(s[i]==s[last])
dp[mask][last][0] = (dp[mask][last][0]+dp[premask][i][1])%mod;
//i是原来的方向,last是翻转的方向
if(t[i]==t[last])
dp[mask][last][1] = (dp[mask][last][1]+dp[premask][i][0])%mod;
//i和last都是翻转的方向
else if(s[i]==t[last])
dp[mask][last][1] = (dp[mask][last][1]+dp[premask][i][1])%mod;
}
}
}
//计算所有可能的情况
ll ans=0;
for(i=0;i<n;i++)
{
ans=(ans+dp[(1<<n)-1][i][0])%mod;
if(s[i]!=t[i])//特殊情况不再统计
ans=(ans+dp[(1<<n)-1][i][1])%mod;
}
printf("%lld\n",ans);
}
}
(Lineup the Dominoes筛子)三维状压的更多相关文章
- Long Dominoes(ZOJ 2563状压dp)
题意:n*m方格用1*3的方格填充(不能重叠)求有多少种填充方法 分析:先想状态,但想来想去就是觉得不能覆盖所有情况,隔了一天,看看题解,原来要用三进制 0 表示横着放或竖放的最后一行,1表示竖放的中 ...
- codevs1358棋盘游戏(状压dp)
1358 棋盘游戏 时间限制: 1 s 空间限制: 64000 KB 题目等级 : 大师 Master 题目描述 Description 这个游戏在一个有10*10个格子的棋盘上进行,初 ...
- 棋盘 || 状压DP
题意:有一个n*m的棋盘(n,m≤80,n*m≤80)要在棋盘上放k(k≤20)个棋子,使得任意两个棋子不相邻(每个棋子最多和周围4个棋子相邻).求合法的方案总数. 思路:对于每一行,如果把没有棋子的 ...
- UOJ #129 / BZOJ 4197 / 洛谷 P2150 - [NOI2015]寿司晚宴 (状压dp+数论+容斥)
题面传送门 题意: 你有一个集合 \(S={2,3,\dots,n}\) 你要选择两个集合 \(A\) 和 \(B\),满足: \(A \subseteq S\),\(B \subseteq S\), ...
- codeforces 342D Xenia and Dominoes(状压dp+容斥)
转载请注明出处: http://www.cnblogs.com/fraud/ ——by fraud D. Xenia and Dominoes Xenia likes puzzles ...
- HDU5731 Solid Dominoes Tilings 状压dp+状压容斥
题意:给定n,m的矩阵,就是求稳定的骨牌完美覆盖,也就是相邻的两行或者两列都至少有一个骨牌 分析:第一步: 如果是单单求骨牌完美覆盖,请先去学基础的插头dp(其实也是基础的状压dp)骨牌覆盖 hiho ...
- 【HDU 4771 Stealing Harry Potter's Precious】BFS+状压
2013杭州区域赛现场赛二水... 类似“胜利大逃亡”的搜索问题,有若干个宝藏分布在不同位置,问从起点遍历过所有k个宝藏的最短时间. 思路就是,从起点出发,搜索到最近的一个宝藏,然后以这个位置为起点, ...
- 状压dp入门
状压dp的含义 在我们解决动态规划题目的时候,dp数组最重要的一维就是保存状态信息,但是有些题目它的具有dp的特性,并且状态较多,如果直接保存的可能需要三维甚至多维数组,这样在题目允许的内存下势必是开 ...
- 状态压缩动态规划 状压DP
总述 状态压缩动态规划,就是我们俗称的状压DP,是利用计算机二进制的性质来描述状态的一种DP方式 很多棋盘问题都运用到了状压,同时,状压也很经常和BFS及DP连用,例题里会给出介绍 有了状态,DP就比 ...
随机推荐
- 通过bat文件 进行mysql 连接 或者 操作涉及 密码的,如果密码 中有 % 号的话要特殊处理
比如我想在bat文件中进行一个数据库的连接 或者进行一个数据库中的 数据 导入或者导出(mysqldump) 这样子都会用到数据库密码, 假如这个数据库的密码 中又有 % 的话就要特殊转义一下才行执行 ...
- Scanner的小细节
Scanner对象是用来接收键盘输入的数据的,可以接收字符串,数字,浮点数,大数等多种数据. Scanner scanner = new Scanner(System.in); System.out. ...
- AJ学IOS 之二维码学习,快速打开相机读取二维码
AJ分享,必须精品 上一篇文章写了怎么生成二维码,这儿就说说怎么读取吧,反正也很简单,iOS封装的太强大了 步骤呢就是这样: 读取二维码需要导入AVFoundation框架#import <AV ...
- 津津的储蓄计划 NOIp提高组2004
这个题目当年困扰了我许久,现在来反思一下 本文为博客园ShyButHandsome的原创作品,转载请注明出处 右边有目录,方便快速浏览 题目描述 津津的零花钱一直都是自己管理.每个月的月初妈妈给津津\ ...
- 用threejs 实现3D物体在浏览器展示
用threejs 实现3D物体在浏览器展示,通过鼠标平移,缩放,键盘箭头按钮左右移动等功能展示. <!DOCTYPE html> <html> <head> < ...
- 分屏神器PoweToys
win+~调用设置分屏界面,shift+软件拖到分屏位置
- Multiple Books多账薄
有些公司因管理需要配置多本账薄,比如管理帐和PRC,那么在Epicor 10中如何实现呢? 1创建 new Book: 2 created a map: Financial Management -& ...
- timer和ScheduledThreadPoolExecutor定时任务和每日固定时间执行
//ScheduledThreadPoolExecutor每三秒执行一次 public static void main(String[] args) { ScheduledThread ...
- webpack 中常用安装插件的一些命令
1:npm install html-webpack-plugin --save-dev //自动快速的帮我们生成HTML.2:npm install css-loader style-loader ...
- [YII2] 增删改查2
一.新增 使用model::save()操作进行新增数据 $user= new User; $user->username =$username; $user->password =$pa ...