传送门

描述:\(一堆筛子,每个筛子两个面,上面有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);
}
}

最新文章

  1. Visual Studio2012打开时弹出“遇到异常:这可能是由某个扩展导致的”错误的解决办法
  2. android 获取文件夹、文件的大小 以B、KB、MB、GB 为单位
  3. GRIDVIEW多行多列合并单元格(合并列)
  4. Spring重点—— IOC 容器中 Bean 的生命周期
  5. Mysql--学习笔记(==》简单查询三)
  6. C++在使用Qt中SLOT宏须要注意的一个小细节
  7. Android开源项目发现--- 安全篇(持续更新)
  8. IIS报500.0错误
  9. 研究一下TForm.WMPaint过程(也得研究WM_ERASEBKGND)——TForm虽然继承自TWinControl,但是自行模仿了TCustomControl的全部行为,一共三种自绘的覆盖方法,比TCustomControl还多一种
  10. Android Studio Debug
  11. 1.3 fractions模块
  12. iOS7编程Cookbook中例15.8中一个小问题
  13. NodeJS之异常处理
  14. 入门嵌入式选择2440?树莓派?STM32?4412开发板?
  15. Mysql必知必会 第三章 使用Mysql
  16. c# 传入c++dll 回调函数输出byte 导致 bug
  17. iptables 最终 第四章
  18. springcloud学习笔记(五)Spring Cloud Actuator
  19. iOS - 标准时间与时间戳相互转换
  20. C++利用系统时间产生的随机数

热门文章

  1. Lua 5.3 -- SOL2.0 用户指南 【2】
  2. Mac OS安装docker
  3. 子域名爆破工具:OneForALL
  4. 不同目录有同名proto文件情况下,protoc生成.cc/.h
  5. vue如何添加jquery?
  6. mybatis源码学习:从SqlSessionFactory到代理对象的生成
  7. 负载均衡服务之HAProxy基础配置(三)
  8. Java 多线程--ThreadLocal Timer ExecutorService
  9. java算法-二分法查找实现
  10. 一张图记住Linux系统常用诊断工具