您的位置:首页 > 其它

成长轨迹61 【ACM算法之路 百炼poj.grids.cn】【动态规划】【2806、1661、2757】

2012-03-12 23:43 441 查看
动态规划算法通常用于求解具有某种最优性质的问题。在这类问题中,可能会有许多可行解。每一个解都对应于一个值,我们希望找到具有最优值的解。

动态规划算法与分治法类似,其基本思想也是将待求解问题分解成若干个子问题,先求解子问题,然后从这些子问题的解得到原问题的解。与分治法不同的是,适合于用动态规划求解的问题,经分解得到子问题往往不是互相独立的。若用分治法来解这类问题,则分解得到的子问题数目太多,有些子问题被重复计算了很多次。如果我们能够保存已解决的子问题的答案,而在需要时再找出已求得的答案,这样就可以避免大量的重复计算,节省时间。

如果k个变量可以构成一个状态的话,并且这k个变量的取值范围分别为n1,n2...那么可以用一个k维数组来存储这些状态k[n1][n2]...

2806:公共子序列

#include <cstdio>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>

char s1[210];
char s2[210];
int len[210][210];
int main()
{
while(scanf("%s %s",s1+1,s2+1)>0)//【0位作为空标识,不使用0位】
//【while(scanf("%s %s",s1,s2)>0)和while(scanf("%s %s",s1,s2))不同!】
{
int len1=strlen(s1+1);//【0位作为空标识,不使用0位】
int len2=strlen(s2+1);
//其中一个字符串长度为0时,
//即以下两种情况时,最长公共子序列的长度均为0
for(int i=0;i<=len1;i++)//j==0
len[i][0]=0;
for(int j=0;j<=len2;j++)//i==0
len[0][j]=0;

for(int i=1;i<=len1;i++)
for(int j=1;j<=len2;j++)
{
if(s1[i]==s2[j])
len[i][j]=len[i-1][j-1]+1;
else
{
len[i][j]=len[i-1][j]>len[i][j-1]?len[i-1][j]:len[i][j-1];
}
}

printf("%d\n",len[len1][len2]);
}
return 0;
}


1661:帮助 Jimmy

#include <cstdio>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>

#define INF 1000000
int k,max,n;
int minleft[1010];
int minright[1010];

struct platform
{
int left;
int right;
int high;
}p[1010];

int cmp(const void * a,const void * b)
{
return ((struct platform *)b)->high - ((struct platform *)a)->high;
}
int min(int k,bool left)
{
int x;
if(left)
{
x=p[k].left;
}
else
{
x=p[k].right;
}
int y=p[k].high;

int i;
for(i=k+1;i<=n;i++)
{
if(p[i].left<=x&&p[i].right>=x)
break;
}
if(i==n+1)//下面没有板
{
if(y>max)
return INF;
else
return y;
}
else if(y-p[i].high>max)
return INF;

int lefttime=y-p[i].high+x-p[i].left;
int righttime=y-p[i].high+p[i].right-x;

if(minleft[i]==-1)//动态规划
minleft[i]=min(i,true);
if(minright[i]==-1)
minright[i]=min(i,false);

lefttime+=minleft[i];
righttime+=minright[i];

return lefttime<righttime?lefttime:righttime;

}
int main()
{
int t;
scanf("%d",&t);
for(int a=0;a<t;a++)
{
memset(minleft,-1,sizeof(minleft));
memset(minright,-1,sizeof(minright));
int x,y;
scanf("%d%d%d%d",&n,&x,&y,&max);
p[0].left=x;
p[0].right=x;
p[0].high=y;
for(int i=1;i<=n;i++)//【注意加上开头一共是n+1个!】
{
scanf("%d%d%d",&p[i].left,&p[i].right,&p[i].high);
}
qsort(p,n+1,sizeof(platform),cmp);//【一定要排序。。。而且一共是n+1个!】

printf("%d\n",min(0,true));

}

return 0;
}


2757:最长上升子序列

#include <cstdio>
int num[1010];
int max[1010];
int main()
{
int n;
scanf("%d",&n);
for(int i=0;i<n;i++)
{
scanf("%d",&num[i]);
}
max[0]=1;
for(int i=1;i<n;i++)
{
int temp=0;
for(int j=0;j<i;j++)
{
if(num[i]>num[j])
{
if(temp<max[j])
//这里是看看比num[i]小的num[j]中哪个上升子序列最长
temp=max[j];
}
}
max[i]=temp+1;//算上自己
}
int nmax=-1;
for(int i=0;i<n;i++)
if(nmax<max[i])
nmax=max[i];
printf("%d\n",nmax);
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐