动态规划--区间DP
1. poj 1141 Brackets Sequence 括号匹配并输出方案
解题思路:
#define _CRT_SECURE_NO_WARNINGS
#include
#include
#include
#include
#include
using namespace std;
#define inf 0x3f3f3f3f
#define maxn 110
int dp[maxn][maxn]; //dp[i][j]表示i->j之间最少插入字符数使之匹配
int path[maxn][maxn]; //path[i][j]表示到达该路径时的选择,-1表示头尾,其他表示中间分开的位置。
char str[maxn];
int len;
void output(int l, int r)
{
if (l > r) return;
if (l == r) //最后一个位置
{
if (str[l] == '(' || str[l] == ')') cout << "()";
else cout << "[]";
return;
}
if (path[l][r] == -1) //相等位置,输出:左-递归中间-右
{
cout << str[l];
output(l + 1, r - 1);
cout << str[r];
}
else
{
output(l, path[l][r]);
output(path[l][r] + 1, r);
}
}
int main(int argc, const char * argv[])
{
while (gets(str) != NULL) //注意scanf不能读空串
{
len = strlen(str);
memset(dp, 0, sizeof(dp));
for (int i = 0; i < len; i++) dp[i][i] = 1; // 一个就再对应匹配一个
for (int l = 1; l < len; l++) //区间长度
{
for(int i = 0, j = l; j < len; i++, j++) //i开始,j结束
{
dp[i][j] = inf;
if (((str[i] == '['&&str[j] == ']') || (str[i] == '('&&str[j] == ')')) &&dp[i][j]>dp[i+1][j-1]) //后面的>必定成立
{
dp[i][j] = dp[i + 1][j - 1];
path[i][j] = -1;
}
for (int pos = i; pos < j; pos++) //中间位置
{
if (dp[i][j] > dp[i][pos] + dp[pos + 1][j])
{
dp[i][j] = dp[i][pos] + dp[pos + 1][j];
path[i][j] = pos;
}
}
}
}
output(0, len - 1);
cout << endl;
}
return 0;
}
2. hdu 4745 Two Rabbits 转化成求回文串
分析:
其实就是求一个环中,非连续最长回文子序列的长度。dp[i][j] = max{ dp[i + 1][j], d[i][j - 1], (if a[i] == a[j]) dp[i + 1][j - 1] + 2 }
但是,这个dp公式仅仅是求出一个序列的非连续最长回文子序列,题目的序列是环状的,有两种思路:
将环倍增成链,求出窗口为n的最长子序列,但这不是最终的解,你可以试看看Sample 2,是只能得出4,因为它在选中的回文外面还可以选中一个当做起点来跳,所以外面得判断找出来的回文外面是否还有可以当起点的石头,即可以找窗口为(n-1)的长度+1。所以解即找 窗口为n的长度或者 窗口为(n-1)的长度+1 的最大值。
不倍增,直接当成一个链求dp,然后把链切成两半,求出两边的回文长度,最大的和就是解。这里不用考虑起点问题,因为两边的回文中点都可以做起点。因为它是两边一起跑 也就是可以是两段回文子序 所以。。只需要求下1-i i+1-n的最长回文串就可以了 这个是可以在之前求总的时候保留下来的
#include
#include
#include
#include
using namespace std;
const int N = 1001<<1;
int dp[N][N];
int a[N];
int n;
int main() {
while (scanf("%d", &n) && n) {
for (int i = 1; i <= n; i++) {
scanf("%d", &a[i]);
a[n + i] = a[i];
}
memset(dp, 0, sizeof(dp));
for (int i = 1; i <= 2 * n; i++)
dp[i][i] = 1;
for (int len = 1; len < 2 * n; len++) {
for (int i = 1; i + len <= 2 * n; i++) {
int j = i + len;
dp[i][j] = max(dp[i + 1][j], max(dp[i][j - 1], (a[i] == a[j] ? dp[i + 1][j - 1] + 2 : 0)));
}
}
int ans = 0;
for (int i = 1; i <= n; i++)
ans = max(ans, dp[i][i + n - 1]);
for (int i = 1; i <= n; i++)
ans = max(ans, dp[i][i + n - 2] + 1);
printf("%d\n", ans);
}
return 0;
}
#define _CRT_SECURE_NO_WARNINGS
#include
#include
#include
#include
#include
using namespace std;
#define inf 0x3f3f3f3f
#define maxn 1100
int dp[maxn][maxn];
int a[maxn], n;
int main()
{
while (cin >> n&&n)
{
memset(dp, 0, sizeof(dp));
for (int i = 0; i < n; i++)
{
cin >> a[i];
dp[i][i] = 1;
}
for (int l = 1; l < n; l++) //区间长度
{
for (int i = 0, j = l; j < n; i++, j++) //区间 i->j之间的回文
{
dp[i][j] = max(dp[i][j], max(dp[i + 1][j], max(dp[i][j - 1], (a[i] == a[j]) ? dp[i + 1][j - 1] + 2 : 0)));
}
}
int ans = 0;
for (int i = 0; i < n; i++)
ans = max(ans, dp[0][i] + dp[i + 1][n - 1]);
cout << ans << endl;
}
return 0;
}
题目大意:
#define _CRT_SECURE_NO_WARNINGS
#include
#include
#include
#include
#include
using namespace std;
#define inf 0x3f3f3f3f
#define maxn 110
int dp[maxn][maxn];
int a[maxn], n;
int sum[maxn];
int main()
{
int t, cas = 1;
cin >> t;
while (t--)
{
cin >> n;
memset(dp, 0, sizeof(dp));
memset(sum, 0, sizeof(sum));
for (int i = 0; i < n; i++)
{
cin >> a[i];
sum[i] = sum[i - 1] + a[i];
}
for (int i = 0; i < n; i++)
{
for (int j = i + 1; j < n; j++)
{
dp[i][j] = inf;
}
}
for (int l = 1; l < n; l++) //区间
{
for (int i = 0, j = l; j < n; i++, j++)
{
for (int k = 1; k <= j - i + 1; k++)
{
dp[i][j] = min(dp[i][j], dp[i + 1][i + k - 1] + (k - 1) * a[i] + dp[i + k][j] + k*(sum[j] - sum[i + k - 1]));
}
}
}
printf("Case #%d: %d\n", cas++, dp[0][n-1]);
}
return 0;
}
zoj 3541 The Last Puzzle 贪心+区间dp
poj 2955 Brackets
hdu 2476 String Printer
zoj 3537 Cake
CF 149D Coloring Brackets
zoj 3469 Food Delivery
End