【上海交大oj】畅畅的牙签袋(状态压缩dp)

1383. 畅畅的牙签袋

题目描述

畅畅说:“你们都说窝脑子瓦特了,我看你们才是脑子瓦特嘞- -”

为了阻挠我们再次揭露他的无chǐ,畅畅妄图破坏我们的显示器,他拿出了自己收集的牙签包装袋,其大小是1×2的矩形,他想用密铺的方式把显示器全部遮挡住。显示器大小是W×H的矩形,畅畅把包装袋背面涂上了胶水,开始一块一块粘到显示器上,要求不能有包装袋重叠,也不能有显示器的某一部分没被遮挡,包装袋的放置只有两种情况:横放和竖放。

畅畅为自己的周密计划洋洋得意之时,脑子又瓦特了,他想让你帮他算算针对每台显示器一共有多少种不同的密铺方式。

说明

  1. 认为显示器是有方向的,即对称的密铺方式要算重复计数,例如 2×2 的显示器密铺方案有两种,一种是2个包装袋都横放,另一种是两个包装袋都竖放。
  2. 不能密铺的则输出0。
  3. 牙签包装袋足够用。

输入格式

输入包括若干行,每行有两个整数Wi和Hi,表示这台显示器大小,输入数据以Wi=Hi=0作为结束,每台显示器大小 1<=Hi,Wi<=11。

输出格式

针对每行输入,每次输出一个整数表示对该显示器密铺的方案总数。Wi=Hi=0时不需要输出。

Sample Input

1 2
1 3
1 4
2 2
2 3
2 4
2 11
4 11
0 0

Sample Output

1
0
1
2
3
5
144
51205

提示

畅畅说如果Wi×Hi是奇数的话可行的方案数就是0了。

畅畅思来想去,认为以行为单位来一行行填充,同时用状态压缩的方式表示每一行的填充状态,0表示空1表示已填充,如一个长为3的行有000,001,010,011,100,101,110,111这样几种状态表示。

畅畅觉得动态规划太难的话,只有暴力搜索了。

畅畅说30%测试点只有一台显示器,70%测试点只有不超过十台显示器,100%测试点只有不超过121台显示器

畅畅说答案很小的,long long就够了



铺砖块问题。每一行为一个阶段,最多有2^11种状态,那么枚举这一行的状态就好了,在这一行的状态确定的情况下,枚举上一行的状态,检查是否兼容(若上一行为0,表示没有铺,则这一行对应位置必须为1,若上一行为1,这一行可以为0也可以为1,但要注意的是,若为1,说明两行的这个位置都是平铺,否则必有其中一个为零(下一行来铺),那么由于是平铺,下一个位置的两行都为1,否则状态不兼容),若兼容则加上对应的数目。

复杂度为h*(2^w)*(2^w)。也可以一个点一个点动归,这个还没实现过,暂时不表。

代码:

 1 #include <iostream>
 2 #include <cstring>
 3 using namespace std;
 4
 5 int w,h;
 6 long long dp[11][1<<11];
 7 long long first_line(int n)
 8 {
 9     int t = 1;
10     for (int i = 1;i <= w;++i,t <<= 1)
11     {
12         if (t & n)
13         {
14             if (i==w || !(n&(t<<1))) return 0;
15             else
16             {
17                 i++;
18                 t <<= 1;
19             }
20         }
21     }
22     return 1;
23 }
24 bool match(int n,int l)
25 {
26     int t = 1;
27     for (int i = 1;i <= w;++i,t<<=1)
28     {
29         if (t & n)
30         {
31             if (t & l) //两行都为1
32             {
33                 if (i==w || !((n & (t<<1)) && (l & (t<<1))) ) return 0;
34                 else
35                 {
36                     i++;t<<=1;
37                 }
38             }
39         }
40         else if (!(t & l)) return 0;
41     }
42     return 1;
43 }
44 int main(){
45
46     while (1)
47     {
48         cin>>w>>h;
49         if (h==0 && w==0) break;
50         if ((h*w)&1) //边长为奇数
51         {
52             cout<<0<<endl;
53             continue;
54         }
55         if (h<w) //减少复杂度
56         {
57             h = h^w;
58             w = h^w;
59             h = h^w;
60         }
61         memset(dp,0,sizeof(dp));
62         for (int i = 0;i < 1<<w;++i) dp[0][i] = first_line(i); //initialize
63         for (int i = 1;i < h;++i)
64             for (int j = 0;j < 1<<w;++j) //当前行状态枚举
65                 for (int k = 0;k < 1<<w;++k) //前一行状态枚举
66                 {
67                     if (match(j,k)) dp[i][j] += dp[i-1][k];
68                 }
69         cout<<dp[h-1][(1<<w)-1]<<endl;
70     }
71
72     return 0;
73 }

时间: 2024-11-10 15:27:51

【上海交大oj】畅畅的牙签袋(状态压缩dp)的相关文章

Light OJ 1037 - Agent 47(预处理状态压缩DP)

题目大意: 有个特工要执行任务,他会遭遇到最多15个目标,特工必须把他们全部杀死.当他杀死一个目标后他可以使用目标的武器来杀死其他人.因此他必须有一个杀人的顺序,使得他开枪的次数最小. 现在给你一个表,代表每种武器对每个目标可以造成多少伤害.并且你知道每个目标的血量.当这个目标的血量小于等于0的时候说明这个目标被杀死了.最初的时候这个特工只有一个枪,这个枪可以对一个目标造成1点伤害. 题目分析: 先把每个状态下最敌人造成的伤害预处理出来,然后再进行一次记忆化搜索. ===============

Light OJ 1406 Assassin`s Creed 状态压缩DP+强连通缩点+最小路径覆盖

题目来源:Light OJ 1406 Assassin`s Creed 题意:有向图 派出最少的人经过全部的城市 而且每一个人不能走别人走过的地方 思路:最少的的人能够走全然图 明显是最小路径覆盖问题 这里可能有环 所以要缩点 可是看例子又发现 一个强连通分量可能要拆分 n最大才15 所以就状态压缩 将全图分成一个个子状态 每一个子状态缩点 求最小路径覆盖 这样就攻克了一个强连通分量拆分的问题 最后状态压缩DP求解最优值 #include <cstdio> #include <cstri

Light OJ 1316 A Wedding Party 最短路+状态压缩DP

题目来源:Light OJ 1316 1316 - A Wedding Party 题意:和HDU 4284 差不多 有一些商店 从起点到终点在走过尽量多商店的情况下求最短路 思路:首先预处理每两点之前的最短路 然后只考虑那些商店 个数小于15嘛 就是TSP问题 状态压缩DP搞一下 状态压缩姿势不对 有必要加强 #include <cstdio> #include <algorithm> #include <queue> #include <vector>

POJ 3254 Corn Fields 状态压缩DP (C++/Java)

http://poj.org/problem?id=3254 题目大意: 一个农民有n行m列的地方,每个格子用1代表可以种草地,而0不可以.放牛只能在有草地的,但是相邻的草地不能同时放牛, 问总共有多少种方法. 思路: 状态压缩的DP. 可以用二进制数字来表示放牧情况并判断该状态是否满足条件. 这题的限制条件有两个: 1.草地限制. 2.相邻限制. 对于草地限制,因为输入的时候1是可以种草地的. 以"11110"草地分析,就只有最后一个是不可以种草的.取反后得00001  .(为啥取反

HDU1565(状态压缩dp)

方格取数(1) Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 8170    Accepted Submission(s): 3095 Problem Description 给你一个n*n的格子的棋盘,每个格子里面有一个非负数.从中取出若干个数,使得任意的两个数所在的格子没有公共边,就是说所取的数所在的2个格子不能相邻,并且取出的数

HDU 3001【状态压缩DP】

题意: 给n个点m条无向边. 要求每个点最多走两次,要访问所有的点给出要求路线中边的权值总和最小. 思路: 三进制状态压缩DP,0代表走了0次,1,2类推. 第一次弄三进制状态压缩DP,感觉重点是对数据的预处理,利用数组分解各个位数,从而达到类似二进制的目的. 然后就是状态的表示,dp[s][i]表示状态s时到达i的最优值. 状态转移也一目了然,不废话. #include<stdio.h> #include<string.h> #include<algorithm> u

Victor and World(spfa+状态压缩dp)

题目连接:http://acm.hdu.edu.cn/showproblem.php?pid=5418 Victor and World Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 262144/131072 K (Java/Others)Total Submission(s): 958    Accepted Submission(s): 431 Problem Description After trying hard fo

poj 3311 Hie with the Pie(状态压缩dp)

Description The Pizazz Pizzeria prides itself in delivering pizzas to its customers as fast as possible. Unfortunately, due to cutbacks, they can afford to hire only one driver to do the deliveries. He will wait for 1 or more (up to 10) orders to be

HDU--1074(状态压缩DP)

典型的状态压缩DP,给出了每件作业的截止时间和花费,求让老师扣分最少的写作业方式.把完成n种作业用状态2^n-1表示,dp[s]表示 完成状态s时,最小扣分.比如“111”,那么可以由“011”,“110”,“101”转移过来,分别表示选了0,1号作业,1,2号作业,0,2号作业. t[s]表示状态S记录的总时间.dp[s] = min{dp[j]+c[k] - d[k]},其中j = i^(1<<k),0<k<n;pre[s]表示状态s完成时,最末尾完成的作业, #include

poj 3254 Corn Fields(状态压缩dp)

Description Farmer John has purchased a lush new rectangular pasture composed of M by N (1 ≤ M ≤ 12; 1 ≤ N ≤ 12) square parcels. He wants to grow some yummy corn for the cows on a number of squares. Regrettably, some of the squares are infertile and