poj 7222 怀表问题(递推+空间压缩)
来源:互联网 发布:网络小贷公司设立条件 编辑:程序博客网 时间:2024/06/10 21:22
poj 7222 怀表问题(递推+空间压缩) 程序设计实习2015上机练习43题第42题
总时间限制: 1000ms 内存限制: 32768kB
描述
怀表是由一个表链和一个表盘连接而成的。同时,表链又是由多个长度为1的表链组件连接而成的。小明现有一个表盘和多个长度为1的表链组件。他希望组合成一个完整的怀表当做生日礼物送给爸爸。
表盘和表链组件的两端都有表扣可以和其它的表链组件或者表盘相连。 一共有两种表扣设计,分别是“L” 和“V”。表链组件和表盘的左右两端可以使用相同的或者不同的表扣设计,因此我们有以下四种不同的表链组件和表盘设计方式,“LL”, “LV”, “VL”, “VV”,如“LV”表示左端的表扣设计是”L”, 右端的表扣设计是“V”。另,表盘和表链是不允许上下左右翻转的。如果把两个表链组件或者一个表链组件和表盘相连接,那么相连部分的表扣设计必须一致。此外,还必须确保表盘可以连接到表链的任意一端。
例子1:表盘是“LV”,共有5个表链组件分别是,“LL”, “LL”, “LV”, “VL”, “VL” 。现在希望组合成长度为4的怀表(表链长度是4)。 有两种正确的表链组合方式:“VLLLLVVL” 和“VLLVVLLL”。而且,对于每一种表链的组合方式,表盘都可以连接到表链的左右两端 (表盘放到表链左端使用V相连,表盘放到表链右端使用L相连)。
例子2: 表盘是“LL”,共有4个表链组件分别是,“LL”, “LV”, “VL”, “VV”。现在希望组合成长度为3的怀表(表链长度是3)。有三种正确的表链组合方式:“LLLVVL”, “LVVLLL”和“LVVVVL”。而且,对于每一种表链的组合方式,表盘都可以接到表链的任一端.
注意怀表的组合方式可能不唯一。每一种表链的组合方式都可以当做是一个由”L”和“V”
组成的字符串。如果两种表链对应的字符串是不匹配的, 那么表链也是不相同的。
输入
标准的输入包含若干组测试数据。每组数据第一行是整数N (0 < N ≤ 40)和K (0 < K ≤ N) 。
N 代表表链组件的个数,K代表要组合成的怀表长度(表链组件的个数)。 接着的N+ 1 行描述表盘(第二行)和表链组件的表扣设计。有四种可能输入: “LV”, “LL”, “VV” 和“VL”。
输出
对于每组测试数据,输出一行。 输出“YES”, 如果可能按照要求组合成怀表,并输出可能的组合方式的数目。如果不能,则输出”NO”.
样例输入
4 4
LV
LL
LV
VL
VL
4 4
VL
LL
LV
VL
VL
样例输出
YES
2
NO
提示
提示: 本题需要使用 long long 数据类型。
最近在重新练习程序设计实习43题,这里剩下一些有难度的题目很好。主要是怀表问题,选择客栈,潘多拉星球的悬浮公寓。前两个有些递推/数学算法在里头,最后一个题目很精彩,虽然算法很熟悉,但是细节不好处理。
哎,首先我审题不仔细的老毛病没有改尤其是当题目似乎比较熟悉的时候就没有动脑子了…各种理解错误,幸好最后又读了一遍题目总算改出了这些低级错误,但是考试的时候恐怕题目一难,心里一慌,时间不够就没有那么幸运了吧。所以以后一定要审题仔细。
这个题目,首先想到递推,用
version 1,用dp实现递推,然后注意到虽然每一个都可能有40个,但是总和不超过40,所以最大值之外只能有20个以内,那么不妨设最大值开头为L,不然所有表反一下号也不影响。那么开数组记载数目分量大概开成[40][40][20][20]就可以了,压缩比约等于4。这种做法压缩比不会太大只能勉强卡进,但是时间上有优势,可以一次预处理一直用过去,而且写起来容易一些。
version 2,用记忆化搜索实现递推,然后不直接管理一个高维数组,相反地自己编号来实现,编号最优大概在
version 1与version 2优劣势可以从运行数据看出,这是两次我自己独立写出来的,都很精彩,希望以后我能多做这些好题,写出精彩的算法。
version 1
Accepted 14360kB 50ms 2081 B G++
#define LL 0#define LV 1#define VL 2#define VV 3#define MAX_N 22#include<stdio.h>#include<memory.h>int n,k;int num[4],target;//L:0,V:1long long int dp[4][MAX_N*2][MAX_N*2][MAX_N][MAX_N],ans;void initialize(){ dp[0][2][1][1][1]=1; dp[1][1][2][1][1]=1; dp[2][1][1][2][1]=1; dp[3][1][1][1][2]=1; for (int ll=1;ll<MAX_N*2;ll++) for (int lv=1;lv<MAX_N;lv++) for (int vl=1;vl<MAX_N;vl++) for (int vv=1;vv<MAX_N;vv++) if (ll+lv+vl+vv>5) { dp[LL][ll][lv][vl][vv]=dp[LV][ll][lv][vl-1][vv]+dp[LL][ll-1][lv][vl][vv]; dp[LV][ll][lv][vl][vv]=dp[LV][ll][lv][vl][vv-1]+dp[LL][ll][lv-1][vl][vv]; dp[VL][ll][lv][vl][vv]=dp[VV][ll][lv][vl-1][vv]+dp[VL][ll-1][lv][vl][vv]; dp[VV][ll][lv][vl][vv]=dp[VV][ll][lv][vl][vv-1]+dp[VL][ll][lv-1][vl][vv]; } return;}inline int code(char ch1,char ch2){ return ((ch1=='V')<<1)+(ch2=='V');}int main(){ //freopen("input.txt","r",stdin); char ch1,ch2; int j,nt[4]; initialize(); /* freopen("output.txt","w",stdout); for (int ll=1;ll<=3;ll++) for (int lv=1;lv<=3;lv++) for (int vl=1;vl<=3;vl++) for (int vv=1;vv<=3;vv++) printf("ll=%d,lv=%d,vl=%d,vv=%d:LL=%d,LV=%d,VL=%d,VV=%d\n", ll-1,lv-1,vl-1,vv-1,dp[LL][ll][lv][vl][vv],dp[LV][ll][lv][vl][vv], dp[VL][ll][lv][vl][vv],dp[VV][ll][lv][vl][vv]); return 0; */ while (scanf("%d %d\n",&n,&k)==2) { ans=0; memset(num,0,sizeof(num)); scanf("%c%c\n",&ch1,&ch2); target=code(ch2,ch1); for (int i=1;i<=n;i++) { scanf("%c%c\n",&ch1,&ch2); num[code(ch1,ch2)]++; } j=0; for (int i=LL;i<=VV;i++) if (num[i]>num[j]) j=i; j=(j&2)+((j&2)>>1); for (int i=0;i<4;i++) nt[i]=num[i]; for (int i=0;i<4;i++) num[i]=nt[i^j]; target^=j; //printf("%d %d %d %d:%d",num[0],num[1],num[2],num[3],target); for (int ll=0;ll<=num[LL];ll++) for (int lv=0;lv<=num[LV] && ll+lv<=k;lv++) for (int vl=0;vl<=num[VL] && ll+lv+vl<=k;vl++) if (k-ll-lv-vl<=num[VV]) ans+=dp[target][ll+1][lv+1][vl+1][k-ll-lv-vl+1]; if (ans) printf("YES\n%lld\n",ans); else printf("NO\n"); } return 0;}
version 2
Accepted 784kB 0ms 1168 B
#include<stdio.h>long long F[20000][4];//必须优化储存方式以防MLE int t[4];//VV:0,VL:1,LV:2,LL:3inline int g(int x,int y,int z,int w){ return (((x*(t[1]+1)+y)*(t[2]+1)+z)*(t[3]+1)+w);}long long f(int* num,int k,int goal){ if (num[0]<0 || num[1]<0 || num[2]<0 || num[3]<0) return 0; if (F[g(num[0],num[1],num[2],num[3])][goal]!=-1) return F[g(num[0],num[1],num[2],num[3])][goal]; if (k==1) return (num[goal]>0); int temp[4]={num[0],num[1],num[2],num[3]}; int l=goal&2,r=goal&1; temp[l]--; F[g(num[0],num[1],num[2],num[3])][goal]=f(temp,k-1,r); temp[l]++; temp[l+1]--; F[g(num[0],num[1],num[2],num[3])][goal]+=f(temp,k-1,2+r); return F[g(num[0],num[1],num[2],num[3])][goal];}int main(){ int n,k,goal; char c1,c2; while (scanf("%d %d\n",&n,&k)!=EOF) { scanf("%c%c\n",&c1,&c2); for (int i=0;i<20000;i++) F[i][0]=F[i][1]=F[i][2]=F[i][3]=-1; t[0]=t[1]=t[2]=t[3]=0; goal=((c2=='L')<<1)+(c1=='L');//要求适配 for (int i=1;i<=n;i++) { scanf("%c%c\n",&c1,&c2); t[((c1=='L')<<1)+(c2=='L')]++; } long long ans=f(t,k,goal); if (ans) printf("YES\n%lld\n",ans); else printf("NO\n"); } return 0;}
- poj 7222 怀表问题(递推+空间压缩)
- OJ 7222 怀表问题__深搜
- poj 2663 递推问题
- 分割空间区域 递推数学问题
- 递推+状态压缩+动态规划-POJ-Mondriaan's Dream
- poj 3420 Quad Tiling(状态压缩矩阵递推)
- poj 2440 DNA(状态压缩递推+矩阵)
- [poj 3254] Corn Fields 状态压缩DP(递推)
- poj Chocolate dp递推+精度问题
- 状态压缩递推
- 递推关系之划分空间问题(hdu 1290&&2050)
- 期末考试-怀表问题(算法基础 第10周)
- POj 3420 Quad Tiling 状态压缩DP+递推+矩阵快速幂
- poj 2704 递推
- poj 1737 递推
- POJ 2029 递推
- POJ 3176 递推
- POJ 2748 推公式循环问题
- 二叉树的非递归建立(二)
- C#中List〈string〉和string[]数组之间的相互转换
- 这是我的第一篇博客
- 14.2.5.5 Change Buffer
- C#转换全角半角方法示例
- poj 7222 怀表问题(递推+空间压缩)
- 爱丽丝的发丝──《爱丽丝惊魂记:疯狂再临》制作点滴
- Mac 教程:告别 Dashboard,教你禁用 OS X 下的仪表盘教程
- 使用ORMLite(框架)创建SQLite数据库
- 音频处理中的尺度--Bark尺度与Mel尺度
- 苹果AppStore审核规则标准指南!
- Git 常用命令大全
- 二叉树的建立和遍历算法 --->树
- C# 十六进制转换ASCII