类型:
数塔
http://acm.hdu.edu.cn/showproblem.php?pid=2084
#include<iostream>
#include<cstdio>
using namespace std;
#define maxn 105
int f[maxn][maxn];
int main()
{
int t,n,i,j;
scanf("%d",&t);
while(t--){
scanf("%d",&n);
for(i = 0; i < n; ++i){
for(j = 0; j <= i; ++j){
scanf("%d",&f[i][j]);
}
}
for(i = n-2; i >= 0; --i){
for(j = 0; j <= i; ++j){
f[i][j] = (f[i][j]+f[i+1][j]) >= (f[i][j]+f[i+1][j+1]) ?
(f[i][j]+f[i+1][j]): (f[i][j]+f[i+1][j+1]);
}
}
printf("%d\n",f[0][0]);
}
}
空间优化
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#define maxn 105
using namespace std;
int dp[maxn], f[maxn][maxn];
int main()
{
int t, n, i, j;
scanf("%d",&t);
while(t--){
scanf("%d",&n);
memset(dp, 0, sizeof(dp));
for(i = 1; i <= n; ++i){
for(j = 1; j <= i; ++j)
scanf("%d",&f[i][j]);
}
for(i = n; i > 0; --i){
for(j = 1; j <= i; ++j){
dp[j] = max(dp[j],dp[j+1]) + f[i][j];
}
}
printf("%d\n",dp[1]);
}
}
最大连续子序列和(要求输出起点终点)
http://acm.hdu.edu.cn/showproblem.php?pid=1003
#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
#define INF 0x3f3f3f3f
int f[100050];
int main()
{
int t, i, j, sum, start, end, flag, ans, n, test;
scanf("%d",&test);
for(n = 1; n <= test; ++n){
scanf("%d",&t);
flag = 1;
for(i = 1; i <= t; ++i){
scanf("%d",&f[i]);
}
ans = -INF;
sum = 0;
j = 1;//记录起点
for(i = 1; i <= t; ++i){
sum += f[i];
if(sum > ans){ //更新最大值
ans = sum;
start = j;
end = i;
}
if(sum < 0){ //更新起点
sum = 0;
j = i + 1;
}
}
printf("Case %d:\n%d %d %d\n",n,ans, start, end);
if(n != test) printf("\n");
}
}
最长上升子序列
http://poj.org/problem?id=2533
需打印序列(并查集):
#include<iostream>
#include<cstdio>
#include<stack>
using namespace std;
#define max 1050
int a[max], dp[max], f[max]; //dp[i]:储存以a[i]为结尾的最大上升子序列 f[i]:存储父结点
//stack<int> num;
int main()
{
int n, i, j, maxn, index; //index记录dp最大时的下标
scanf("%d", &n);
for(i = 1; i <= n; ++i){
scanf("%d", &a[i]);
}
dp[1] = 1;
//f[1] = 1;
int ans = 1;
//index = 1;
for(i = 2; i <= n; ++i){
maxn = 0;
//f[i] = i;
for(j = 1; j < i; ++j){
if(a[i] > a[j] && maxn < dp[j]){
maxn = dp[j];
//f[i] = j;
}
}
dp[i] = maxn + 1;
if(ans < dp[i]){
//index = i;
ans = dp[i];
}
}
printf("%d\n",ans);
//i = index;
//while(f[i] != i){
// num.push(a[i]);
// i = f[i];
//}
//num.push(a[i]);
//while(!num.empty()){
// printf("%d ",num.top());
// num.pop();
//}
printf("\n");
}
不需要打印序列(二分查找)(nlogn):
https://cn.vjudge.net/problem/HDU-1025
从1~n遍历,dp[len]存储长度为len的最长上升子序列的结尾。现在用数组f存储序列, 若dp[len] <= f[i]则把f[i]加入到dp[++len],相反遍历数组dp,找到一个dp[j] < f[i] < dp[j+1], 然后dp[j+1] = f[i]。(其实就是把大的数加入到dp的结尾, 小的数进行替换, 替换过程中的查找用二分查找@_@)
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
#define maxn 500050
#define INF 0x3f3f3f3f
int dp[maxn], f[maxn];
int main()
{
int i , j, k, n, x, y, ans, times = 0, left, right, mid, temp;
while(~scanf("%d", &n)){
for(i = 1; i <= n; ++i){
scanf("%d %d", &x, &y);
f[x] = y;
}
printf("Case %d:\n", ++times);
memset(dp, 0, sizeof(dp));
ans = 1;
dp[1] = f[1];
for(i = 2; i <= n; ++i){
if(dp[ans] <= f[i]){
dp[++ans] = f[i];
}
else{
left = 1; right = ans;
while(right >= left){
mid = (left + right)/2;
if(dp[mid] > f[i])
right = mid - 1;
else
left = mid + 1;
}
dp[left] = f[i];
}
}
if(ans != 1)
printf("My king, at most %d roads can be built.\n\n",ans);
else
printf("My king, at most 1 road can be built.\n\n");
}
}
最长公共子序列
http://acm.hdu.edu.cn/showproblem.php?pid=1159
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define maxn 1050
char str1[maxn], str2[maxn];
int dp[maxn][maxn];//dp[i][j]:str1[i]与str2[j]为结尾的最大公共子序列
int main()
{
while(~scanf("%s %s", str1, str2)){
int len1 = strlen(str1), len2 = strlen(str2), ans = 0;
for(int i = 1; i <= len1; ++i){
for(int j = 1; j <= len2; ++j){
if(str1[i-1] == str2[j-1]){
dp[i][j] = dp[i-1][j-1] + 1;
}
else{
dp[i][j] = max(dp[i-1][j], dp[i][j-1]);
}
if(ans < dp[i][j]){
ans = dp[i][j];
}
}
}
printf("%d\n", ans);
}
}
01背包
http://acm.hdu.edu.cn/showproblem.php?pid=2602
二维( j 必须从 0 开始):
#include<iostream>
#include<cstdio>
#include <algorithm>
#include<cstring>
#define maxn 1050
using namespace std;
int dp[maxn][maxn];
int main()
{
int t, n, v, i, j;
scanf("%d", &t);
while(t--){
int va[1050] = {0}, vo[1050] = {0};
memset(dp,0,sizeof(dp));
scanf("%d %d", &n, &v);
for(i = 1; i <= n; ++i){
scanf("%d", &va[i]);
}
for(i = 1; i <= n; ++i){
scanf("%d", &vo[i]);
}
for(i = 1; i <= n; ++i){
for(j = 0; j <= v; ++j){
if(vo[i] <= j)
dp[i][j] = max(dp[i-1][j],(dp[i-1][j-vo[i]]+va[i]));
else{
dp[i][j] = dp[i-1][j];
}
}
}
printf("%d\n",dp[n][v]);
}
}
一维:
#include<iostream>
#include<cstdio>
#include <algorithm>
using namespace std;
int main()
{
long long t, n, v, i, j;
scanf("%lld", &t);
while(t--){
long long va[1050] = {0}, vo[1050] = {0}, dp[1050] = {0};
scanf("%lld %lld", &n, &v);
for(i = 1; i <= n; ++i){
scanf("%lld", &va[i]);
}
for(i = 1; i <= n; ++i){
scanf("%lld", &vo[i]);
}
for(j = 1; j <= n; ++j){
for(i = v; i >= vo[j]; --i){
dp[i] = max(dp[i],(dp[i-vo[j]] + va[j]));
//cout << "j :" << j << " i: " << i << " dp:"<< dp[i]<<endl;
}
}
printf("%lld\n",dp[v]);
}
}
多重背包:
http://acm.hdu.edu.cn/showproblem.php?pid=2844
二进制优化+拆解(要求出具体最大值):
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
#define maxn 100050
#define INF 0x3f3f3f3f
int dp[maxn], a[maxn], c[maxn];
int main()
{
int n, m, i, j, k, ans;
while(~scanf("%d %d",&n, &m) && (n!=0||m!=0)){
memset(dp, -INF,sizeof(dp));
memset(a, 0,sizeof(a));
memset(c, 0,sizeof(c));
for(i = 1; i <= n; ++i){
scanf("%d", &a[i]);
}
for(j = 1; j <= n; ++j){
scanf("%d", &c[j]);
}
dp[0] = 1;
for(i = 1; i <= n; ++i){
if(a[i] * c[i] >= m){
for(j = a[i]; j <= m; ++j){
dp[j] = max(dp[j], dp[j-a[i]] + a[i]);
}
}
else{
for(k = 1; k <= c[i]; k *= 2){
for(j = m; j >= a[i] * k; --j){
dp[j] = max(dp[j], dp[j-a[i]*k]+a[i]*k);
}
c[i] -= k;
}
if(c[i] > 0){
for(j = m; j >= a[i] * c[i]; --j){
dp[j] = max(dp[j], dp[j-a[i]*c[i]]+a[i]*c[i]);
}
}
}
}
ans = 0;
for(j = 1; j <= m; ++j){
if(dp[j] >= 0){
ans++;
}
}
printf("%d\n", ans);
//printf("%d\n",dp[m]);
}
}
只要求出最大组合数:
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
#define maxn 100050
#define INF 0x3f3f3f3f
int dp[maxn], num[maxn], a[maxn], c[maxn];
int main()
{
int n, m, i, j, k, ans;
while(~scanf("%d %d",&n, &m) && (n!=0||m!=0)){
memset(dp, 0,sizeof(dp));
for(i = 1; i <= n; ++i){
scanf("%d", &a[i]);
}
for(j = 1; j <= n; ++j){
scanf("%d", &c[j]);
}
dp[0] = 1;
ans = 0;
for(i = 1; i <= n; ++i){
memset(num, 0, sizeof(num));
for(j = a[i]; j <= m; ++j){
if(!dp[j] && c[i] > num[j - a[i]]&&dp[j-a[i]]){
num[j] = num[j-a[i]] + 1;
dp[j] = 1;
++ans;
}
}
}
printf("%d\n", ans);
}
}
完全背包:
http://acm.hdu.edu.cn/showproblem.php?pid=1114
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
#define maxn 10050
#define INF 0x3f3f3f3f
int dp[maxn], value[1000], weight[1000];
int main()
{
int t, e, f, i, j, w, n, k, ans, less;
scanf("%d",&t);
while(t--){
scanf("%d %d",&e, &f);
w = f - e;
scanf("%d",&n);
for(i = 0; i < n; ++i){
scanf("%d %d",&value[i], &weight[i]);
}
memset(dp,INF,sizeof(dp));
dp[0] = 0;
for(i = 0; i < n; ++i){
for(j = weight[i]; j <= w; ++j){
dp[j] = min(dp[j],dp[j-weight[i]]+value[i]);
}
}
if(dp[w] >= INF)
printf("This is impossible.\n");
else
printf("The minimum amount of money in the piggy-bank is %d.\n",dp[w]);
}
}