区间dp问题,通常给出一个序列,用dp[ i ][ j ] 表示序列为ai,a(i + 1)...aj时的答案,而较长的序列的答案由较短的序列的答案递推得到,让人想到矩阵连乘顺序问题。
所以解题的时候会用到3个循环:
第一层枚举序列长度 jj
第二层枚举序列开头的位置 i
第三层枚举序列 [i, i + jj ] 中间点 k,其中第三层有时是不需要的
下面是一些区间dp入门题,大同小异,这里就不给出思路了,看下代码大概就明白了
题目:POJ 2955 http://poj.org/problem?id=2955
代码:
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <algorithm>
#define MOD 1000000007
#define INF 0x7fffffff
using namespace std;
int dp[105][105];
char s[105];
int match(int l, int r)
{
if(s[l] == '(' && s[r] == ')') return 1;
if(s[l] == '[' && s[r] == ']') return 1;
return 0;
}
int main()
{
#ifdef LOCAL
freopen("dpdata.txt", "r", stdin);
#endif
while(scanf("%s", s) != EOF && s[0] != 'e')
{
int len = strlen(s);
memset(dp, 0, sizeof(dp));
for(int jj = 1; jj < len; jj++)
{
for(int i = 0; i + jj < len; i++)
{
int j = i + jj;
if(match(i, j))
{
dp[i][j] = max(dp[i][j], dp[i + 1][j - 1] + 2);
}
for(int k = i; k < j; k++)
{
dp[i][j] = max(dp[i][j], dp[i][k] + dp[k + 1][j]);
}
//printf("dp[%d][%d]=%d\n", i, j, dp[i][j]);
}
}
printf("%d\n", dp[0][len - 1]);
}
return 0;
}
题目:HDU 2476 http://acm.hdu.edu.cn/showproblem.php?pid=2476
代码:
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <algorithm>
#define MOD 1000000007
#define INF 0x7fffffff
using namespace std;
char A[105], B[105];
int dp[105][105], ans[105];
int main()
{
#ifdef LOCAL
freopen("dpdata.txt", "r", stdin);
#endif
int l, r;
while(scanf("%s%s", A, B) != EOF)
{
int len = strlen(A);
memset(dp, 0, sizeof(dp));
for(int jj = 0; jj < len; jj++)
{
for(int i = 0; i + jj < len; i++)
{
int j = i + jj;
dp[i][j] = dp[i + 1][j] + 1;
for(int k = i + 1; k <= j; k++)
{
if(B[i] == B[k])
dp[i][j] = min(dp[i][j], dp[i + 1][k] + dp[k + 1][j]);
}
//printf("dp[%d][%d]=%d\n", i, j, dp[i][j]);
}
}
for(int i = 0; i < len; i++)
ans[i] = dp[0][i];
for(int i = 0; i < len; i++)
{
if(B[i] == A[i])
{
if(i == 0)
ans[i] = 0;
else
ans[i] = ans[i - 1];
}
else
{
for(int j = 0; j < i; j++)
{
ans[i] = min(ans[i], ans[j] + dp[j + 1][i]);
}
}
}
printf("%d\n", ans[len - 1]);
}
return 0;
}
题目:POJ 3186 http://poj.org/problem?id=3186
代码:
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <algorithm>
#define MOD 1000000007
#define INF 0x7fffffff
using namespace std;
int v[2005], sum[2005], dp[2005][2005], a[2005][2005];
int main()
{
#ifdef LOCAL
freopen("dpdata.txt", "r", stdin);
#endif
int n;
while(scanf("%d", &n) != EOF)
{
memset(dp, 0, sizeof(dp));
memset(a, 0, sizeof(a));
for(int i = 0; i < n; i++)
{
scanf("%d", &v[i]);
dp[i][i] = v[i];
a[i][i] = v[i];
//printf("a[%d][%d]=%d\n", i, i, a[i][i]);
}
sum[0] = v[0];
for(int i = 1; i < n; i++)
{
sum[i] = sum[i - 1] + v[i];
a[0][i] = sum[i];
//printf("a[0][%d]=%d\n", i, a[0][i]);
}
for(int i = 1; i < n; i++)
{
for(int j = i + 1; j < n; j++)
{
a[i][j] = sum[j] - sum[i - 1];
//printf("a[%d][%d]=%d\n", i, j, a[i][j]);
}
}
for(int jj = 1; jj < n; jj++)
{
for(int i = 0; i + jj < n; i++)
{
int j = i + jj;
dp[i][j] = max(dp[i][j], dp[i + 1][j] + a[i + 1][j] + a[i][i]);
dp[i][j] = max(dp[i][j], dp[i][j - 1] + a[i][j - 1] + a[j][j]);
//printf("dp[%d][%d]=%d\n", i, j, dp[i][j]);
}
}
printf("%d\n", dp[0][n -1]);
}
return 0;
}
题目:POJ 1651 http://poj.org/problem?id=1651
代码:
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <algorithm>
#define MOD 1000000007
#define INF 0x7fffffff
using namespace std;
int dp[105][105];
int main()
{
#ifdef LOCAL
freopen("dpdata.txt", "r", stdin);
#endif
int n, a[105];
while(scanf("%d", &n) != EOF)
{
for(int i = 0; i < n; i++)
{
scanf("%d", &a[i]);
}
for(int i = 0; i <= n; i++)
{
for(int j = 0; j <= n; j++)
dp[i][j] = 100000100;
}
for(int i = 1; i < n - 1; i++)
{
dp[i - 1][i + 1] = a[i - 1] * a[i] * a[i + 1];
//printf("dp[%d][%d]=%d\n", i - 1, i + 1, dp[i - 1][i + 1]);
}
for(int jj = 3; jj < n; jj++)
{
for(int i = 0; i + jj < n; i++)
{
int j = i + jj;
for(int k = i + 2; k + 1< j; k++)
{
dp[i][j] = min(dp[i][j], dp[i][k] + dp[k][j]
+ a[i] * a[k] * a[j]);
}
dp[i][j] = min(dp[i][j], dp[i][j - 1] + a[i] * a[j - 1] * a[j]);
dp[i][j] = min(dp[i][j], dp[i + 1][j] + a[i] * a[i + 1] * a[j]);
//printf("dp[%d][%d]=%d\n", i, j, dp[i][j]);
}
}
printf("%d\n", dp[0][n - 1]);
}
return 0;
}
题目:HDU 4632 http://acm.hdu.edu.cn/showproblem.php?pid=4632
代码:
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <algorithm>
#define MOD 10007
#define INF 0x7fffffff
using namespace std;
char s[1005];
int dp[1005][1005];
int main()
{
#ifdef LOCAL
freopen("dpdata.txt", "r", stdin);
#endif
int t;
scanf("%d", &t);
for(int cas = 1; cas <= t; cas++)
{
scanf("%s", s);
int len = strlen(s);
memset(dp, 0, sizeof(dp));
for(int i = 0; i < len; i++)
{
dp[i][i] = 1;
}
for(int jj = 1; jj < len; jj++)
{
for(int i = 0; i + jj < len; i++)
{
int j = i + jj;
dp[i][j] = max(dp[i][j], dp[i][j - 1] + dp[i + 1][j]
- dp[i + 1][j - 1] + MOD);
if(s[i] == s[j])
{
dp[i][j] += dp[i + 1][j - 1] + 1 + MOD;
}
dp[i][j] %= MOD;
}
}
printf("Case %d: %d\n", cas, dp[0][len - 1]);
}
return 0;
}
题目:HDU 4283 http://acm.hdu.edu.cn/showproblem.php?pid=4283
代码:
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <algorithm>
#define MOD 1000000007
#define INF 0x7fffffff
using namespace std;
int d[105], dp[105][105], a[105][105], sum[105];
int main()
{
#ifdef LOCAL
freopen("dpdata.txt", "r", stdin);
#endif
int t, n;
scanf("%d", &t);
for(int cas = 1; cas <= t; cas++)
{
scanf(" %d", &n);
memset(dp, 0, sizeof(dp));
memset(a, 0, sizeof(a));
for(int i = 0; i < n; i++)
{
scanf("%d", &d[i]);
dp[i][i] = 0;
a[i][i] = d[i];
}
sum[0] = d[0];
for(int i = 1; i < n; i++)
{
sum[i] = a[0][i] = sum[i - 1] + d[i];
}
for(int i = 0; i < n; i++)
{
for(int j = i + 1; j < n; j++)
{
dp[i][j] = 1000010;
if(i > 0)a[i][j] = sum[j] - sum[i - 1];
//printf("a[%d][%d]=%d\n", i, j, a[i][j]);
}
}
for(int j = 1; j < n; j++)
{
for(int i = 0; i + j < n; i++)
{
//dp[i][i + j] = min(dp[i][i + j], dp[i + 1][i + j] + a[i + 1][i + j]);
for(int k = 0; k <= j; k++)
{
dp[i][i + j] = min(dp[i][i + j], dp[i + 1][i + k] + k * a[i][i]
+ dp[i + k + 1][i + j] + (k + 1) * a[i + k + 1][i + j]);
}
//dp[i][i + j] = min(dp[i][i + j], dp[i + 1][i + j] + a[i][i] * j);
//printf("dp[%d][%d]=%d\n", i, i + j, dp[i][i + j]);
}
}
printf("Case #%d: %d\n", cas, dp[0][n - 1]);
}
return 0;
}
代码:
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <algorithm>
#define MOD 1000000007
#define INF 1 << 30 - 1
typedef long long ll;
using namespace std;
ll dp[70][70], a[70];
int main()
{
#ifdef LOCAL
freopen("dpdata.txt", "r", stdin);
#endif
int t, n;
//printf("INF=%I64d\n", INF);
scanf("%d", &t);
while(t--)
{
scanf("%d", &n);
memset(dp, 0, sizeof(dp));
for(int i = 0; i < n; i++)
{
scanf("%I64d", &a[i]);
}
for(int i = 0; i < n; i++)
{
dp[i][i] = a[i] * 2;
for(int j = i + 1; j < n; j++)
{
dp[i][j] = INF;
}
}
for(int jj = 1; jj < n; jj++)
{
for(int i = 0; i + jj < n; i++)
{
int j = i + jj;
for(int k = i; k < j; k++)
{
dp[i][j] = min(dp[i][j], dp[i][k] + dp[k + 1][j]);
if(jj <= 19)
{
ll cur = a[i];
for(int cnt = 1; cnt <= (jj + 1); cnt++)
cur *= 2;
dp[i][j] = min(dp[i][j], cur);
}
}
//printf("dp[%d][%d]=%d\n", i, j, dp[i][j]);
}
}
printf("%I64d\n", dp[0][n - 1]);
}
return 0;
}
题目:POJ 3280 http://poj.org/problem?id=3280
代码:
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <algorithm>
#define MOD 1000000007
#define INF 0x7fffffff - 20010
using namespace std;
char s[2005];
int add[30], del[30], dp[2005][2005];
int main()
{
#ifdef LOCAL
freopen("dpdata.txt", "r", stdin);
#endif
int n, m;
char c;
while(scanf("%d %d ", &n, &m) != EOF)
{
memset(add, 0, sizeof(add));
memset(del, 0, sizeof(del));
memset(dp, 0, sizeof(dp));
for(int i = 0; i <= m; i++)
{
for(int j = i + 1; j <= m; j++)
{
dp[i][j] = INF;
}
}
scanf("%s", s);
for(int i = 0; i < n; i++)
{
scanf(" %c", &c);
scanf("%d%d", &add[c - 'a'], &del[c - 'a']);
}
for(int jj = 1; jj < m; jj++)
{
for(int i = 0; i + jj < m; i++)
{
int j = i + jj;
if(s[i] != s[j])
{
dp[i][j] = min(dp[i][j], dp[i + 1][j] + add[s[i] - 'a']);
dp[i][j] = min(dp[i][j], dp[i][j - 1] + add[s[j] - 'a']);
dp[i][j] = min(dp[i][j], dp[i + 1][j] + del[s[i] - 'a']);
dp[i][j] = min(dp[i][j], dp[i][j - 1] + del[s[j] - 'a']);
}
else
{
dp[i][j] = min(dp[i][j], dp[i + 1][j - 1]);
}
//printf("dp[%d][%d] = %d\n", i, j, dp[i][j]);
}
}
printf("%d\n", dp[0][m - 1]);
}
return 0;
}