kuangbin带你飞dp专题-基础dp
dp
HDU - 1257 最少拦截系统
最长递增子序列
1 #include<iostream> 2 using namespace std; 3 const int maxn=1e7; 4 int a[maxn],dp[maxn],n; 5 6 int main() 7 { 8 while(cin>>n) { 9 for (int i = 1; i <= n; i++)cin >> a[i]; 10 for (int i = 1; i <= n; i++)dp[i] = 1; 11 for (int i = 2; i <= n; i++) 12 for (int j = 1; j < i; j++) { 13 if (a[i] > a[j]) 14 dp[i] = max(dp[i], dp[j] + 1); 15 } 16 int ans = 0; 17 for (int i = 1; i <= n; i++)ans = max(ans, dp[i]); 18 cout << ans << endl; 19 } 20 return 0; 21 }
HDU - 1029 Ignatius and the Princess IV
HDU - 1069 Monkey and Banana
POJ - 1458 Common Subsequence
最长公共子序列
dp[i][j] = 0 i==0 || j==0
= max(dp[i][j], dp[i-1][j-1]+1) a[i-1]==b[i-1]
= max(dp[i-1][j], dp[i][j-1]) a[i-1]!=b[i-1]
1 #include<string> 2 #include <iostream> 3 using namespace std; 4 const int maxn=1e4+2; 5 int dp[maxn][maxn]; 6 int main() 7 { 8 string s1,s2; 9 while(cin>>s1>>s2) 10 { 11 int len1=s1.size(); 12 int len2=s2.size(); 13 for(int i=0;i<=len1;i++) 14 for(int j=0;j<=len2;j++) 15 dp[i][j]=0; 16 for(int i=0;i<=len1;i++) 17 for(int j=0;j<=len2;j++) 18 { 19 if((i==0)||(j==0))continue; 20 else if(s1[i-1]==s2[j-1]) 21 dp[i][j]=max(dp[i][j],dp[i-1][j-1]+1); 22 else 23 { 24 dp[i][j]=max(dp[i][j],dp[i][j-1]); 25 dp[i][j]=max(dp[i][j],dp[i-1][j]); 26 } 27 } 28 cout<<dp[len1][len2]<<endl; 29 } 30 return 0; 31 }
POJ - 2533 Longest Ordered Subsequence
1 while(cin>>n) 2 { 3 for(int i=1;i<=n;i++)cin>>a[i]; 4 for(int i=1;i<=n;i++)dp[i]=1; 5 for(int i=2;i<=n;i++) 6 { 7 for(int j=1;j<i;j++) 8 { 9 if(a[i]>a[j]) 10 dp[i]=max(dp[i],dp[j]+1); 11 } 12 ans=max(ans,dp[i]); 13 } 14 cout<<ans<<endl; 15 }
HDU - 1003 Max Sum
1 #include<iostream> 2 #include <algorithm> 3 #include <cstring> 4 using namespace std; 5 const int maxn=1e5+2; 6 long long dp[maxn],a[maxn],ans=-0xfffffffffffff; 7 int n,t=0,T=0,l,r; 8 9 int main() 10 { 11 cin>>n; 12 while(n--) 13 { 14 cin>>t; 15 T++; 16 for(int i=1;i<=t;i++)cin>>a[i]; 17 for(int i=-1;i<=t;i++)dp[i]=a[i]; 18 for(int i=2;i<=t;i++) 19 dp[i]=max(dp[i-1]+a[i],dp[i]); 20 for(int i=1;i<=t;i++) 21 { 22 if(dp[i]>ans){ 23 ans=max(ans,dp[i]); 24 r=i; 25 } 26 } 27 long long sum=0; 28 for(int i=r;i>=1;i--) { 29 sum += a[i]; 30 if (sum == ans) { 31 l = i; 32 } 33 } 34 if(T!=1)cout<<endl; 35 cout<<"Case "<<T<<":"<<endl; 36 cout<<ans<<" "<<l<<" "<<r<<endl; 37 } 38 return 0; 39 }
HDU - 3421 Max Sum II
HDU - 1024 Max Sum Plus Plus
HDU - 1244 Max Sum Plus Plus Plus
HDU - 1087 Super Jumping! Jumping! Jumping!
HDU - 1114 Piggy-Bank
HDU - 1176 免费馅饼
HDU - 1160 FatMouse's Speed
POJ - 1661 Help Jimmy
HDU - 1260 Tickets
POJ - 3186 Treats for the Cows
HDU - 1078 FatMouse and Cheese
HDU - 2859 Phalanx
POJ - 3616 Milking Time
POJ - 3666 Making the Grade
HDU - 1074 Doing Homework
UVA - 11367 Full Tank?
POJ - 1015 Jury Compromise
题意:选m人:控方和辩方会根据对候选人的喜欢程度,给候选人打分,分值从0到20。为了公平起见,法官选出陪审团的原则是:选出的m个人,必须满足辩方总分D和控方总分P的差的绝对值|D-P|最小。如果有多种选择方案的 |D-P| 值相同,那么选辩控双方总分之和D+P最大的方案。
输出:要求输出这m个人的辩方总值D和控方总值P,并升序输出他们的编号
思路:
辩方总分和控方总分之差称为“辩控差”,辩方总分和控方总分之和称为“辩控和”。
第i个候选人的辩方总分和控方总分之差记为V(i),之和记为S(i)。
状态:dp[j][k]表示,取j个候选人,使其辩控差为k的所有方案中,辩控和最大的方案的辩控和。
如果没法选j个人,使其辩控差为k,那么dp(j, k)的值就为-1。
求:dp[m][k] (-20×m ≤ k ≤ 20×m)
转移方程:dp[j][k]= max ( dp[j-1][k-V[i]]+S[i], dp[j][k] )
方案dp[j][k]是由某个可行的方案 dp[j-1][x] 演化而来,可行方案 dp[j-1][x] 能演化成方案 dp[j][k] 的必要条件是:存在某个候选人i,i 在方案 dp[j-1][x] 中没有被选上,且x+V(i) = k。在所有满足该必要条件的dp[j-1][x]中,选出 dp[j-1][x]+ S(i) 的值最大的。
程序中没有求绝对值而是将辩控差都加上修正值fix=400,以免下标为负数导致出错,此时初始条件修正为dp[0][fix] = 0,其他均为-1。DP后,从第m行的dp(m, fix)开始往两边搜索最小|D-P| 即可,第一个不为dp[m][k]!=-1的位置k就是最小|D-P|的所在。
1 #include <iostream>
#include <string.h> 2 #include <algorithm> 3 using namespace std; 4 int f[30][1000]; 5 //f[j][k]表示:取j个候选人,使其辩控差为k的方案中 6 //辩控和最大的那个方案(该方案称为“方案f(j,k)”)的控辩和 7 int Path[30][1000]; 8 //Path数组用来记录选了哪些人 9 //方案f(j,k)中最后选的那个候选人的编号,记在Path[j][k]中 10 int P[300];//控方打分 11 int D[300]; //辩方打分 12 13 int Answer[30];//存放最终方案的人选 14 15 int main() 16 { 17 int i,j,k; 18 int t1,t2; 19 int n,m; 20 int MinP_D;//辩控双方总分一样时的辩控差 21 int Case;//测试数据编号 22 Case=0; 23 while(scanf("%d %d",&n,&m)) 24 { 25 if(n==0&&m==0)break; 26 Case++; 27 for(i=1;i<=n;i++) 28 scanf("%d %d",&P[i],&D[i]); 29 memset(f,-1,sizeof(f)); 30 memset(Path,0,sizeof(Path)); 31 MinP_D=m*20;//题目中的辩控差为0,对应于程序中的辩控差为m*20 32 f[0][MinP_D]=0; 33 for(j=0;j<m;j++)//每次循环选出第j个人,共要选出m人 34 { 35 for(k=0;k<=MinP_D*2;k++)//可能的辩控差为[0,nMinP_D*2] 36 if(f[j][k]>=0)//方案f[j][k]可行 37 { 38 for(i=1;i<=n;i++) 39 if(f[j][k]+P[i]+D[i]>f[j+1][k+P[i]-D[i]]) 40 { 41 t1=j;t2=k; 42 while(t1>0&&Path[t1][t2]!=i)//验证i是否在前面出现过 43 { 44 t2-=P[Path[t1][t2]]-D[Path[t1][t2]]; 45 t1--; 46 } 47 if(t1==0) 48 { 49 f[j+1][k+P[i]-D[i]]=f[j][k]+P[i]+D[i]; 50 Path[j+1][k+P[i]-D[i]]=i; 51 } 52 } 53 } 54 } 55 i=MinP_D; 56 j=0; 57 while(f[m][i+j]<0&&f[m][i-j]<0) // 从中间向两边开始找辩控差最小和最大 58 j++; 59 if(f[m][i+j]>f[m][i-j]) 60 k=i+j; 61 else 62 k=i-j; 63 printf("Jury #%d\n",Case); 64 printf("Best jury has value %d for prosecution and value %d for defence:\n",(k-MinP_D+f[m][k])/2,(f[m][k]-k+MinP_D)/2); 65 for(i=1;i<=m;i++) 66 { 67 Answer[i]=Path[m-i+1][k]; 68 k-=P[Answer[i]]-D[Answer[i]]; 69 } 70 sort(Answer+1,Answer+1+m); 71 for(i=1;i<=m;i++) 72 printf(" %d",Answer[i]); 73 printf("\n\n"); 74 } 75 return 0; 76 }