您的位置:首页 > 其它

动态规划的问题总结

2017-06-30 00:01 99 查看
1、dp[个数][weight] (例子:poj 1837 Balance)

dp[i][w]=relate to (dp[i-1][w-c[j]])

这道题中dp存储的不是weight,而是方法个数

#include<iostream>
#include<cstdio>
#include<cstring>
#include<vector>
#include<queue>
#include<algorithm>
#define MAXNUM 15000
using namespace std;
int dp[25][MAXNUM], C, G, good[25], w[25];
int main()
{
//freopen("1.txt", "r", stdin);
int i, j, k, a, b, c, sum, cases;
scanf("%d%d", &C, &G);
for (i = 1; i <= C; i++)
scanf("%d", &good[i]);
for (i = 1; i <= G; i++)
scanf("%d", &w[i]);
dp[0][7500] = 1;
for (i = 1; i <= G; i++)
{
for (j = 0; j <= MAXNUM; j++)
{
if (dp[i - 1][j])
{
for (k = 1; k <= C; k++)
dp[i][j + good[k] * w[i]] += dp[i - 1][j];
}

}
}
printf("%d\n", dp[G][7500]);
return 0;
}


2、dp[所有可能的值] (例子:poj 1276 Cash Machine)

if(dp[i]) dp[i+w[t]*k]=1; 有时候Bool类型更好

#include<iostream>
#include<cstdio>
#include<cstring>
#include<vector>
#include<queue>
#include<algorithm>
#define CASH 100005
using namespace std;
bool dp[CASH];
int N, cash, n[20], D[20];
int main()
{
//freopen("1.txt", "r", stdin);
int i, j, k, a, b, c, res;
while (scanf("%d%d", &cash, &N) != EOF)
{
memset(dp, 0, sizeof(dp));
memset(n, 0, sizeof(n));
memset(D, 0, sizeof(D));
for (i = 0; i < N; i++)
scanf("%d%d", &n[i], &D[i]);
if (!N || !cash)
{
printf("0\n");
continue;
}
res = 0;
dp[0] = 1;
for (i = 0; i < N; i++)
{
for (j = res; j >= 0; j--)
{
if (dp[j])
for (k = 1; k <= n[i]; k++)
{
a = j + k*D[i];
if (a <= cash)
{
dp[a] = 1;
res = max(res, a);
}
}
}
}
printf("%d\n", res);
}
return 0;
}


3、3276 The Cow Lexicon

dp[i]=dp[j]+w[i,j] / dp[i]=dp[j]+w[j,i] 一个是倒着,一个是顺着

dp[i]=dp[i+1]+1 //把这个给删除了

dp[i]=dp[j]+j-i-len //i~j的串删除一些字符后能和Len匹配的

#include<iostream>
#include<vector>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
#include<string>
#include<math.h>
using namespace std;
int dp[305], W, L;
char ss[305];
string strs[610];
int main()
{
//freopen("1.txt", "r", stdin);
int i, j, k, t, a, b, len, flag;
while (scanf("%d%d", &W, &L) != EOF)
{
memset(dp, 0, sizeof(dp));
//memset(ss, 0, sizeof(ss));
scanf("%s", ss);
for (i = 0; i < W; i++)
cin >> strs[i];

for (i = L - 1; i >= 0; i--)
{
dp[i] = dp[i + 1] + 1;
for (j = 0; j < W; j++)
{
len = strs[j].length();
if (len <= L - i&&ss[i] == strs[j][0])
{
int pm = i;
int pi = 0;
while (pi < len&&pm < L)
{
if (ss[pm++] == strs[j][pi])
pi++;
if (pi == len)
{
dp[i] = min(dp[i], dp[pm] + pm - i - len);
break;
}
}
}
}
}
printf("%d\n", dp[0]);
}
return 0;
}


4 、POJ 1836 Alignment

难一些的最大上升子序列



顺着求一次最大上升子序列dpl,倒着求一次最大上升子序列dpr,然后求dpl[i]+dp=i”>j的最大值

(别人的代码,参考博客:http://blog.csdn.net/lin375691011/article/details/11137083)

#include <stdio.h>
#include <string.h>
const int MAX=1005;
int main()
{
int n,dpl[MAX],dpr[MAX];
double hi[MAX];
while(scanf("%d",&n)!=EOF)
{
int i,j;
for(i=0; i<n; i++)
{
scanf("%lf",&hi[i]);
}
memset(dpr,0,sizeof(dpr));
memset(dpl,0,sizeof(dpl));
dpl[0]=1;
for(i=1;i<n;i++)
{
dpl[i]=1;
for(j=i-1;j>=0;j--)
{
if(hi[j]<hi[i]&&dpl[j]+1>dpl[i])
{
dpl[i]=dpl[j]+1;
}
}
}
dpr[n-1]=1;
for(i=n-2;i>=0;i--)
{
dpr[i]=1;
for(j=i+1;j<=n-1;j++)
{
if(hi[j]<hi[i]&&dpr[j]+1>dpr[i])
{
dpr[i]=dpr[j]+1;
}
}
}
int ans=dpl[n-1];
for(i=0;i<n-1;i++)
{
for(j=i+1;j<n;j++)
{
if(dpl[i]+dpr[j]>ans)
{
ans=dpl[i]+dpr[j];
}
}
}
printf("%d\n",n-ans);
}
return 0;
}


5 、POJ 1260 Pearls

题目有点难懂,懂了之后就是dp[i]=dp[j]+w[i,j]的最小值,遍历j

#include<iostream>
#include<vector>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
#include<string>
#include<math.h>
using namespace std;
int price[110], num[110], dp[110], sum[110];
int main()
{
//freopen("1.txt", "r", stdin);
int i, j, k, t, tmp, cases;
scanf("%d", &cases);
while (cases > 0)
{
memset(price, 0, sizeof(price));
memset(num, 0, sizeof(num));
memset(sum, 0, sizeof(sum));
memset(dp, 0, sizeof(dp));
scanf("%d", &k);
for (i = 1; i <= k; i++)
{
scanf("%d%d", &num[i], &price[i]);
sum[i] = sum[i - 1] + num[i];
}

dp[1] = (num[1] + 10) * price[1];
for (i = 2; i <= k; i++)
{
dp[i] = (num[i] + 10) * price[i] + dp[i - 1];
for (j = 0; j < i - 1; j++)
{
tmp = (sum[i] - sum[j] + 10)*price[i] + dp[j];
dp[i] = min(dp[i], tmp);
}
}
cases--;
printf("%d\n", dp[k]);
}
return 0;
}


dp 数组的memset很重要!!!!!!!

6 、POJ 1080 Human Gene Functions

编辑距离的变式

#include<iostream>
#include<vector>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
#include<string>
#include<math.h>
#define MAXNUM 250
using namespace std;
int dp[MAXNUM][MAXNUM];
char str1[MAXNUM], str2[MAXNUM];
int rep1[MAXNUM], rep2[MAXNUM];
int insert[4] = { -3, -4, -2, -1 };
int contrast[4][4] = { { 5, -1, -2, -1 }, { -1, 5, -3, -2 }, { -2, -3, 5, -2 }, { -1, -2, -2, 5 } };
int main()
{
//freopen("1.txt", "r", stdin);
int i, j, k, t, tmp1, tmp2, cases, len1, len2;
scanf("%d", &cases);
while (cases > 0)
{
memset(rep1, 0, sizeof(rep1));
memset(rep2, 0, sizeof(rep2));
memset(dp, 0, sizeof(dp));
scanf("%d%s", &len1, str1 + 1);
for (i = 1; i <= len1; i++)
{
if (str1[i] == 'A')
rep1[i] = 0;
else if (str1[i] == 'C')
rep1[i] = 1;
else if (str1[i] == 'G')
rep1[i] = 2;
else if (str1[i] == 'T')
rep1[i] = 3;
}
scanf("%d%s", &len2, str2 + 1);
for (i = 1; i <= len2; i++)
{
if (str2[i] == 'A')
rep2[i] = 0;
else if (str2[i] == 'C')
rep2[i] = 1;
else if (str2[i] == 'G')
rep2[i] = 2;
else if (str2[i] == 'T')
rep2[i] = 3;
}
dp[0][0] = 0;
for (i = 1; i <= len1; i++)
{
dp[i][0] = insert[rep1[i]] + dp[i - 1][0];
}
for (i = 1; i <= len2; i++)
{
dp[0][i] = insert[rep2[i]] + dp[0][i - 1];
}
for (i = 1; i <= len1; i++)
for (j = 1; j <= len2; j++)
{
tmp1 = dp[i][j - 1] + insert[rep2[j]];
tmp2 = dp[i - 1][j] + insert[rep1[i]];
tmp1 = max(tmp1, tmp2);
tmp2 = dp[i - 1][j - 1] + contrast[rep1[i]][rep2[j]];
dp[i][j] = max(tmp1, tmp2);;
}
printf("%d\n", dp[len1][len2]);
cases--;

}
return 0;
}


7、poj 1159 Palindrome

这道题我以为是一个字符串和他的反向字符串求编辑距离的问题,但是仔细想想就不对,ab字符串和ba字符串的编辑距离就是2,而实际上需要添加的字符个数其实只有1个,所以仔细想想应该也可以用编辑距离的模板去套用,不过目的是求一个字符串和他的反向字符串得公共最大字符串长度n,然后用字符串的长度L减去n就是最后的结果,比如说Ab3bd与db3bA的公共子串是b3b,为3,5-3=2就为最后的结果。

Accepted 184K 891MS

//这也告诉了我一种新的关于求公共子序列的方法哈哈

#include<iostream>
#include<vector>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
#include<string>
#include<math.h>
#define MAXNUM 5050
using namespace std;
int dp[2][MAXNUM], N;
char str1[MAXNUM], str2[MAXNUM];
int main()
{
//freopen("1.txt", "r", stdin);
int i, j, k, t, tmp1, tmp2, cases, len;
while (scanf("%d", &N) != EOF)
{
memset(dp, 0, sizeof(dp));
memset(str1, 0, sizeof(str1));
memset(str2, 0, sizeof(str2));
scanf("%s", str1 + 1);
len = N;
for (i = 1; i <= len; i++)
str2[i] = str1[len + 1 - i];
for (i = 1; i <= len; i++)
{
dp[1][0] = 0;
for (j = 1; j <= len; j++)
{
if (str1[i] == str2[j])
dp[1][j] = dp[0][j - 1] + 1;
else
{
tmp1 = max(dp[0][j], dp[1][j - 1]);
dp[1][j] = max(tmp1, dp[0][j - 1]);
}

}
for (j = 0; j <= len; j++)
dp[0][j] = dp[1][j];
}
printf("%d\n", N - dp[1][len]);
}
return 0;
}


动态规划—->最优二分检索树

http://blog.csdn.net/ncepuzhuang/article/details/8924369

代码:

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