动态规划 POJ 1037 A decorative fence
来源:互联网 发布:淘宝暗语的农夫是什么 编辑:程序博客网 时间:2024/06/05 02:24
这道题还是比较难想出来的,我也搞了好久才搞懂,而且是在问了大牛的基础上才搞清楚的。反而觉得黑书上没有讲清楚,现在我们来具体看看这道题的思路吧。
我们这样看一个符合条件的序列,例如一个长度为n的序列,当我们去定了前面的k项的时候,后面剩下的n-k项与1到n-k的符合条件的序列有一个一一对应的关系。这便是我们使用动态规划的动机,存在重叠子问题。于是我们如下定义状态:
dp[i][j][0]表示以i为开头的,长度为j的上升的合法的序列的总数
dp[i][j][1]表示以i为开头的,长度为j的下降的合法的序列的总数
我们当前的长度为j的序列的子问题正好与j-1长度的合法序列相对应(这一点需要仔细理解),于是可以确定我们状态的定义和转移时合法的。
dp[i][j][0]=sum{dp[x][j-1][1]} (j-1>=x>=i)
dp[i][j][1]=sum{dp[x][j-1][0]} (i>x>=1)
我们预处理出来上面的dp值之后,就是构造解了。
对于这种构造排列的问题,我们通常是逐位减去高位所确定的合法排列的个数。对于这道题我们也是一样,但是对于第一个起点我们要特殊处理,判断是上升还是下降。之后就直接减去符合条件的排列数,一次确定每一位就行了。
最后输出解的时候,我们要注意,我们存的是在剩下的可选的数中的第几大的数,于是我们要反回来映射到1-n之间的数,反正数据量比较小,直接暴力枚举。
思路就是这样,不明白可以看看代码:
#include <iostream>#include <cstring>#include <cstdlib>#include <cstdio>using namespace std;const int Max=25;typedef long long LL;LL dp[Max][Max][2];void init(int n){ memset(dp,0,sizeof(dp)); dp[1][1][0]=1;//up dp[1][1][1]=1;//down for(int j=2;j<=n;j++) { for(int i=1;i<=j;i++) { for(int x=i;x<j;x++) { dp[i][j][0]+=dp[x][j-1][1]; } for(int x=1;x<i;x++) { dp[i][j][1]+=dp[x][j-1][0]; } } }}int ans[Max];void solve(int n,LL c){ int tn=n; int flag,cur; LL sum=0LL; for(int i=1;i<=n;i++) { if(sum+dp[i][n][0]+dp[i][n][1]>=c) { ans[1]=i; c-=sum; cur=i; break; } sum+=(dp[i][n][0]+dp[i][n][1]); } if(c<=dp[cur][n][1]) flag=1; else{c-=dp[cur][n][1];flag=0;} --n; int len=2; while(n>0) { if(flag==0) { for(int i=cur;i<=n;i++) { if(dp[i][n][1]>=c) { cur=i; ans[len++]=cur; break; } c-=dp[i][n][1]; } } else { for(int i=1;i<cur;i++) { if(dp[i][n][0]>=c) { cur=i; ans[len++]=cur; break; } c-=dp[i][n][0]; } } --n; flag=1-flag; } int vis[Max]={0}; for(int i=1;i<=tn;i++) { for(int j=1;j<=tn;j++) { if(vis[j]==0) { ans[i]--; if(ans[i]==0) { printf("%d%c",j,i==tn?'\n':' '); vis[j]=1; break; } } } }}int main(){ int T,n; LL c; scanf("%d",&T); init(20); while(T--) { scanf("%d %lld",&n,&c); solve(n,c); } return 0;}
- 动态规划 POJ 1037 A decorative fence
- POJ 1037 A decorative fence 动态规划
- POJ 1037 A decorative fence(美丽栅栏)__动态规划
- poj 1037 A decorative fence
- POJ 1037 A decorative fence
- POJ 1037 A decorative fence
- poj 1037 A decorative fence
- poj 1037 A decorative fence
- POJ1037 A decorative fence 【动态规划】
- dp+计数 poj-1037-A decorative fence
- POJ 1037 A decorative fence(dp)
- POJ 1037 A decorative fence DP
- 【poj 1037】A decorative fence 排列dp
- POJ 1037 A decorative fence 笔记
- 1037 A decorative fence
- Pku1037 A decorative fence 动态规划+递推
- poj 1037 A decorative fence dp+序列构造
- poj 1037 A decorative fence(递推+组合计数/数学)
- C#中的字符串简单倒序
- Makefile中指示符“include”、“-include”和“sinclude”的区别
- stage.frameRate改变帧频
- struts2分页技术
- C#编码规范
- 动态规划 POJ 1037 A decorative fence
- mybatis limit的使用
- html DIV 滚动条
- Tuxedo性能测试基础
- 关于cytoscape插件
- CRC原理及其逆向分析方法
- Linux下的多线程编程
- 2.兵器谱
- 获取URL中的文件后缀