您的位置:首页 > 其它

poj 1221 UNIMODAL PALINDROMIC DECOMPOSITIONS 动态规划

2010-03-12 19:36 423 查看
UNIMODALPALINDROMICDECOMPOSITIONS

TimeLimit:1000MSMemoryLimit:65536K
TotalSubmissions:2580Accepted:1200
Description
AsequenceofpositiveintegersisPalindromicifitreadsthesameforwardandbackward.Forexample:
231115137371151123
1123477107743211
APalindromicsequenceisUnimodalPalindromicifthevaluesdonotdecreaseuptothemiddlevalueandthen(sincethesequenceispalindromic)donotincreasefromthemiddletotheendForexample,thefirstexamplesequenceaboveisNOTUnimodalPalindromicwhilethesecondexampleis.
AUnimodalPalindromicsequenceisaUnimodalPalindromicDecompositionofanintegerN,ifthesumoftheintegersinthesequenceisN.Forexample,alloftheUnimodalPalindromicDecompositionsofthefirstfewintegersaregivenbelow:
1:(1)
2:(2),(11)
3:(3),(111)
4:(4),(121),(22),(1111)
5:(5),(131),(11111)
6:(6),(141),(222),(11211),(33),
(1221),(111111)
7:(7),(151),(232),(11311),(1111111)
8:(8),(161),(242),(11411),(12221),
(1112111),(44),(1331),(2222),
(112211),(11111111)

Writeaprogram,whichcomputesthenumberofUnimodalPalindromicDecompositionsofaninteger.
Input
Inputconsistsofasequenceofpositiveintegers,oneperlineendingwitha0(zero)indicatingtheend.
Output
Foreachinputvalueexceptthelast,theoutputisalinecontainingtheinputvaluefollowedbyaspace,thenthenumberofUnimodalPalindromicDecompositionsoftheinputvalue.Seetheexampleonthenextpage.
SampleInput
2
3
4
5
6
7
8
10
23
24
131
213
92
0

SampleOutput
22
32
44
53
67
75
811
1017
23104
24199
1315010688
2131055852590
92331143

题解只写给新手看,大牛略过。

最近一直在作动态规划的题,但这道还是想了好久,水啊。

先研究一下每一组数据时怎样由前面的推出的。

比如6的(6),(141),(222),(11211),(33),
(1221),(111111)一共7个。
将6拆成两个相同的数和另一个大于这个数的数或者0(真拗口)。直接看下面就好:

1、6=1+1+4。那么他可以将4的所有情况两边都加1变成6的解(141),(11211),(1221),(111111)共4个。

2、6=2+2+2。那么他可以将2的所有最小值大于等于2的情况两边加2即将(2)变成(2,2,2)共1个

3、6=3+3+0。注意只有另一个数是0的时候才可以这么拆如5=2+2+1是不可以的。那么他可以将0的所有情况两边加3,变成3,3共1个。这里默认0的情况总数是1.

4、6本身自己(6)就是一组共1个

所以6的解共4+1+1+1=7个。

由以上分析得到状态转移方程s[i][j]=s[i-2*j][j]+s[i][j+1];(1<=j<=i/2)

其中i表示数据的和,就是题中的n,j表示i的所有解中所有数大于等于j的情况总数(之所以这样定义可以参考上面分析中的第2步)

具体实现

1、将s[i][j](i>=j>i/2)内容预处理成1(因为对于j>i/2时所有的s[i][j]都是1,如s[6][4]=s[6][5]=s[6][6]=1只有(6)一个)。

2、将s[i][j](i<j)内容预处理成0(因为根据定义j不可能比i大。)

3、将s[0][j]内容预处理成1(因为当需要调用s[0][j]时表示一个数拆成了完全相同的两个数,结果当然是一个了,)

4、在for(i=2;i<=nax;i++)的每次循环中加入for(j=i/2;j>=1;j--)循环,每次逆推结果

程序实现过程

比如i=6时

1、j=3s[6][3]=s[6-3*2][3]+s[6][4]=1+1=2;表示6中解大于3的有两种(3,3)(6);

2、j=2s[6][2]=s[2][2]+s[6][3]=1+2=3;

3、j=1s[6][1]=s[4][1]+s[6][2]=4+3=7;s[6][1]中储存n=6时的所有解

。。。。

具体代码

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
__int64s[301][301];
intn;
intmain()
{
inti,j,t;
memset(s,0,sizeof(0));
for(i=1;i<=300;i++)
for(j=i;j>=0;j--)
s[i][j]=1;
for(i=0;i<=300;i++)s[0][i]=1;
for(i=2;i<=300;i++)
for(j=i/2;j>=1;j--)
{
s[i][j]=s[i-2*j][j]+s[i][j+1];
}
while(scanf("%d",&n),n!=0)
{
printf("%d%I64d/n",n,s
[1]);
}
}


细节:s的内容可能超出int的范围需要用int64才可以ac


内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: