SDUT_线性dp联系结题报告:

1001:求最大子段和,关键是判断当前位置选与不选的状态状态转移方程:dp[i]=max(dp[i-1]+a[i],a[i]);还要记录起点与终点(单独开了一个结构体记录到达每个点的起点与终点)

http://acm.hdu.edu.cn/showproblem.php?pid=1003

View Code
 1 #include <cstdio>
2 #include <cstring>
3 int dp[100007],a[100007];
4 struct node
5 {
6 int s,e;
7 }p[100007];
8 int main()
9 {
10 int t,n,cas=1,i;
11 scanf("%d",&t);
12 while(t--)
13 {
14 memset(dp,0,sizeof(dp));
15 scanf("%d",&n);
16 printf("Case %d:\n",cas++);
17 for(i=0;i<n;i++)
18 scanf("%d",&a[i]);
19 dp[0]=a[0];
20 p[0].s=p[0].e=0;
21 for(i=1;i<n;i++)
22 {
23 if(dp[i-1]+a[i]>=a[i])
24 {
25 dp[i]=dp[i-1]+a[i];
26 p[i].s=p[i-1].s;
27 p[i].e=i;
28 }
29 else
30 {
31 dp[i]=a[i];
32 p[i].s=i;
33 p[i].e=i;
34 }
35 }
36 int max=dp[0];
37 int tx=0;
38 for(i=1;i<n;i++)
39 {
40 if(dp[i]>max)
41 {
42 max=dp[i];
43 tx=i;
44 }
45 }
46 printf("%d %d %d\n",max,p[tx].s+1,p[tx].e+1);
47 if(t>0)
48 printf("\n");
49 }
50 return 0;
51 }

1002:也是一个求最大子段和的问题,不过就是把二维的转化成一维的数组然后按照一维最大子段和,最后找出最大的。

http://acm.hdu.edu.cn/showproblem.php?pid=1081

View Code
 1 #include <cstdio>
2 #include <cstring>
3 #include <iostream>
4 int sum[107],f[107][107];
5 int n;
6 int get_s(int dp[])
7 {
8 int i;
9 for(i=1;i<n;i++)
10 {
11 if(dp[i-1]+dp[i]>dp[i])
12 dp[i]=dp[i-1]+dp[i];
13 }
14 int max=dp[0];
15 for(i=1;i<n;i++)
16 {
17 if(max<dp[i])
18 max=dp[i];
19 }
20 return max;
21 }
22 int main()
23 {
24 int i,j,k;
25 while(~scanf("%d",&n))
26 {
27 for(i=0;i<n;i++)
28 {
29 for(j=0;j<n;j++)
30 scanf("%d",&f[i][j]);
31 }
32 for(i=1;i<n;i++)
33 {
34 for(j=0;j<n;j++)
35 f[i][j]+=f[i-1][j];
36 }
37 int max=-9999999;
38 for(i=0;i<n;i++)
39 {
40 for(j=i+1;j<n;j++)
41 {
42 for(k=0;k<n;k++)
43 sum[k]=f[j][k]-f[i][k];//向一维转化
44 int su=get_s(sum);//调用一维求法的函数
45 if(max<su)
46 max=su;
47 }
48 }
49 printf("%d\n",max);
50 }
51 return 0;
52 }

1003 原来做过的一题目,LCIS求最长上升子序列o(n^2)超时,要用o(nlogn)的方(二分查找)法,虽然明白了了,但是细节上还是出了很多错误。。

http://acm.hdu.edu.cn/showproblem.php?pid=1025

View Code
 1 #include <cstdio>
2 #include <cstring>
3 #include <iostream>
4 #include <algorithm>
5 using namespace std;
6 const int max_s = 500007;
7 int a[max_s],len[max_s];
8 int B_search(int num,int l,int r)
9 {
10 while(l<=r)
11 {
12 int m=(l+r)>>1;
13 if(len[m]>num) r=m-1;
14 else if(len[m]<num) l=m+1;
15 else if(len[m]==num) return m;
16 }
17 return l;
18 }
19 int main()
20 {
21 int n,i,x,y,cas=1;
22 while(~scanf("%d",&n))
23 {
24 printf("Case %d:\n",cas++);
25 for(i=0;i<=n;i++)
26 {
27 a[i]=0;
28 len[i]=0;
29 }
30 for(i=0;i<n;i++)
31 {
32 scanf("%d%d",&x,&y);
33 a[x]=y;
34 }
35 if(n==1)
36 {
37 printf("My king, at most 1 road can be built.\n\n");
38 continue;
39 }
40 len[1]=a[1];//len[i]记录的长度为i的最小的a[];
41 int k=1;
42 for(i=2;i<=n;i++)
43 {
44 if(a[i]>len[k])
45 {
46 len[++k]=a[i];
47 }
48 else
49 {
50 int pos=B_search(a[i],1,k);
51 len[pos]=a[i];
52 }
53 }
54 if(k==1)
55 printf("My king, at most %d road can be built.\n\n",k);
56 else
57 printf("My king, at most %d roads can be built.\n\n",k);
58 }
59 return 0;
60 }

1004:才开始以为直接打表推出来然后排序就可以,结果我悲催了,这样算的中间过程会出现超出(—int64\long lng )的范围的数据,最后还是要应该是每次选出最小的来加到数组里面的:

f[i]=min(l1*2,l2*3,l3*5,l4*7);

选出来最小的以后对四个只里面等于(这里很重要)min的L要++,这样选出来的就不会超数据,了而且还不用排序,还有英语,MD悲剧啊。。很多都不会啊。。

11---19;单独拿出来+th其他的1+st.2+nd,3+rd 其他加th主要的区别在两位数上,三位以上就直接按两位处理,面临这样的英语实在蛋疼啊。。

http://acm.hdu.edu.cn/showproblem.php?pid=1058

View Code
 1 #include <iostream>
2 #include <cstdio>
3 #include <algorithm>
4 using namespace std;
5 const int max_s = 58508;
6 __int64 f[max_s];
7 int len;
8 int l1,l2,l3,l4;
9 void Min(__int64 a,__int64 b,__int64 c,__int64 d)
10 {
11 __int64 m=20000000001;
12 if(m>a) m=a;
13 if(m>b) m=b;
14 if(m>c) m=c;
15 if(m>d) m=d;
16 f[++len]=m;
17 if(m==a) l1++;
18 if(m==b) l2++;
19 if(m==c) l3++;
20 if(m==d) l4++;
21
22 }
23 void init()
24 {
25 len=1;
26 f[1]=1;
27 l1=l2=l3=l4=1;
28 while(len<=5842)
29 {
30 Min(f[l1]*2,f[l2]*3,f[l3]*5,f[l4]*7);
31 }
32 /*for(int i=1;i<=5842;i++)
33 printf("%I64d ",f[i]);
34 printf("\n");*/
35 }
36 int main()
37 {
38 int n;
39 init();
40 while(scanf("%d",&n),n)
41 {
42 if((n%100)/10!=1)
43 {
44 if(n%10==1)
45 printf("The %dst humble number is %I64d.\n",n,f[n]);
46 else if(n%10==2)
47 printf("The %dnd humble number is %I64d.\n",n,f[n]);
48 else if(n%10==3)
49 printf("The %drd humble number is %I64d.\n",n,f[n]);
50 else
51 printf("The %dth humble number is %I64d.\n",n,f[n]);
52 }
53 else
54 {
55 printf("The %dth humble number is %I64d.\n",n,f[n]);
56 }
57 }
58 return 0;
59 }


1005 以前没大接触过LCS,看了看《算法导论》,隐约明白了,可是做起这道题来,还是很费劲,我是看的结题报告(鄙视我吧)

将题目转化成算法导论上的那个矩阵:

首先将s1,s2转换到a,b里面这样方便处理,并且把,0,0位置空出来了,

f[i][j]=max(f[i-1][j-1]+map[a[i]][b[j]],f[i-1][j]+map[a[i]][4],f[i][j-1]+map[4][b[j]]);

  1.s1取第i个字母,s2取“-”:f[i-1,j] + map[s1[i],'-']
  2.s1取“-”,s2取第j个字母:f[i,j-1] + map['-',s2[j]]
  3.s1取第i个字母,s2取第j个字母:f[i-1,j-1] + map[s1[i],s2[j]]
  即f[i,j] = max(f[i-1,j] + score[s1[i],'-'], f[i,j-1] + smap['-',s2[j]], f[i-1,j-1] + map[s1[i],s2[j]]);
View Code
 1 #include <cstdio>
2 #include <cstring>
3 #include <iostream>
4 using namespace std;
5 int map[5][5]={{5,-1,-2,-1,-3},{-1,5,-3,-2,-4},{-2,-3,5,-2,-2},{-1,-2,-2,5,-1},{ -3,-4,-2,-1,0}};
6 int a[107],b[107];
7 char s1[107],s2[107];
8 int f[107][107];
9 int Max(int x,int y,int z)
10 {
11 int tmp=-99999999;
12 if(tmp<x) tmp=x;
13 if(tmp<y) tmp=y;
14 if(tmp<z) tmp=z;
15 return tmp;
16 }
17 int main()
18 {
19 int t,n,m,i,j;
20 scanf("%d",&t);
21 while(t--)
22 {
23 cin>>n>>s1;
24 cin>>m>>s2;
25 for(i=0;i<n;i++)
26 {
27 if(s1[i]=='A') a[i+1]=0;
28 else if(s1[i]=='C') a[i+1]=1;
29 else if(s1[i]=='G') a[i+1]=2;
30 else if(s1[i]=='T')a[i+1]=3;
31 }
32 for(i=0;i<m;i++)
33 {
34 if(s2[i]=='A') b[i+1]=0;
35 else if(s2[i]=='C') b[i+1]=1;
36 else if(s2[i]=='G') b[i+1]=2;
37 else if(s2[i]=='T')b[i+1]=3;
38 }
39 f[0][0]=0;
40 for(i=1;i<=n;i++) f[i][0]=f[i-1][0]+map[a[i]][4];
41 for(j=1;j<=m;j++) f[0][j]=f[0][j-1]+map[4][b[j]];
42 for(i=1;i<=n;i++)
43 {
44 for(j=1;j<=m;j++)
45 {
46 int f1=f[i-1][j-1]+map[a[i]][b[j]];
47 int f2=f[i-1][j]+map[a[i]][4];
48 int f3=f[i][j-1]+map[4][b[j]];
49 f[i][j]=Max(f1,f2,f3);
50 }
51 }
52 cout<<f[n][m]<<endl;
53 }
54 return 0;
55 }





评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值