区间dp(石子合并and括号匹配)
2018-03-23 19:29
609 查看
就是把大区间划分为小区间然后取小区间的最优值处理石子合并和括号匹配(1). 石子合并①.n堆石子,每堆有a[i]个,每次合并两堆,需要体力为相邻两堆石子之和
每次合并最小的两堆就好了SDNUOJ1013石子合并简化版
[cpp] view plain copy#include<cstdio>
#include<algorithm>
#include<iostream>
#include<cstring>
using namespace std;
int main()
{
int n;
int sum;
int x[10010];
while(cin>>n&&n != 0)
{
sum = 0;
memset(x, 0, sizeof(x));
for(int i = 0; i < n; i++)
cin>>x[i];
sort(x, x+n);
for(int i = n-1; i > 0; i--)
{
x[i-1] = x[i-1] + x[i];
sum=(sum % 1000000007 + x[i-1] % 1000000007) % 1000000007;
}
cout<<sum<<endl;
}
return 0;
}
②.n堆石子直线排列,每堆有a[i]个,每次合并相邻两堆,需要体力为相邻两堆石子之和sum[i]是前i堆总的石子个数状态方程:dp[i][j] = min(dp[i][j], dp[i][k] + dp[k+1][j] + sum[j] - sum[i-1]);[cpp] view plain copy
[cpp] view plain copy/*for(int i = 0; i < n; i++)
dp[i][i]=0;*/
for(int t = 1; t < n; t++)
{
for(int i = 0; i < n-t; i++)
{
int j = i + t;
dp[i][j] = inf;
for(int k = i; k < j; k++)
dp[i][j] = min(dp[i][j], dp[i][k]+dp[k+1][j] + sum[j] - sum[i-1]);
}
}
SDNUOJ1045石子合并1朴素算法[cpp] view plain copy#include<cstdio>
#include<iostream>
using namespace std;
#define inf 0xffffff
int main()
{
int n;
int a[210];
int sum[210];
int dp[210][210];
scanf("%d",&n);
for(int i = 0; i < n; i++)
{
scanf("%d", &a[i]);
sum[i]=sum[i-1] + a[i];
}
for(int i = 0; i < n; i++)
dp[i][i] = 0;
for(int t = 1; t < n; t++)
{
for(int i = 0; i < n-t; i++)
{
int j = i + t;
dp[i][j] = inf;
for(int k = i; k < j; k++)
dp[i][j] = min(dp[i][j], dp[i][k]+dp[k+1][j] + sum[j] - sum[i-1]);
}
}
printf("%d", dp[0][n-1]);
return 0;
}
这个时间复杂度......o(n^3)四边形不等式优化[cpp] view plain copy/*for(int i=1; i<=n; i++)
{
dp[i][i] = 0;
p[i][i] = i;
} */
for(int len=1; len<n; len++)
{
for(int i=1; i+len<=n; i++)
{
int end = i+len;
int tmp = INF;
int k = 0;
for(int j=p[i][end-1]; j<=p[i+1][end]; j++)
{
if(dp[i][j] + dp[j+1][end] + sum[end] - sum[i-1] < tmp)
{
tmp = dp[i][j] + dp[j+1][end] + sum[end] - sum[i-1];
k = j; //找到令dp最小的k记下来
}
}
dp[i][end] = tmp;
p[i][end] = k;
}
}
ac代码[cpp] view plain copy#include<cstdio>
#include<iostream>
using namespace std;
#define inf 0xffffff
int main()
{
int n;
int a[210];
int sum[210];
int dp[210][210];
int p[210][210];
scanf("%d",&n);
for(int i = 1; i <= n; i++)
{
scanf("%d", &a[i]);
sum[i]=sum[i-1] + a[i];
}
for(int i=1; i<=n; i++)
{
dp[i][i] = 0;
p[i][i] = i;
}
for(int len=1; len<n; len++)
{
for(int i=1; i+len<=n; i++)
{
int end = i+len;
int tmp = inf;
int k = 0;
for(int j=p[i][end-1]; j<=p[i+1][end]; j++)
{
if(dp[i][j] + dp[j+1][end] + sum[end] - sum[i-1] < tmp)
{
tmp = dp[i][j] + dp[j+1][end] + sum[end] - sum[i-1];
k = j;
}
}
dp[i][end] = tmp;
p[i][end] = k;
}
}
printf("%d", dp[1]
);
return 0;
}
时间复杂度大概为o(n^2)了完了以后GarsiaWachs算法
哇咔咔妙哇存stone[ ]数组,从左往右,找一个k满足stone[k-1] <= stone[k+1],完了以后合并stone[k]和stone[k-1],再从当前位置开始向左找最大的j,使其满足stone[j] > stone[k]+stone[k-1],插到j的后面。重复,直到只剩下一堆石子......假设stone[-1]和stone
是正无穷的
ac代码[cpp] view plain copy#include <cstdio>
#include <iostream>
using namespace std;
int stone[205];
int n,t,ans;
void combine(int k)
{
int tmp = stone[k] + stone[k-1];
ans += tmp;
for(int i = k; i < t-1; i++)
stone[i] = stone[i+1];
t--;
int j = 0;
for(j = k - 1; j > 0 && stone[j-1] < tmp; j--)
stone[j] = stone[j-1];
stone[j] = tmp;
while(j >= 2 && stone[j] >= stone[j-2])
{
int d = t - j;
combine(j-1);
j = t - d;
}
}
int main()
{
scanf("%d", &n);
for(int i = 0; i < n; i++)
{
scanf("%d", stone + i);
}
t = 1;
ans = 0;
for(int i = 1; i < n; i++)
{
stone[t++] = stone[i];
while(t >= 3 && stone[t-3] <= stone[t-1])
combine(t-2);
}
while(t > 1) combine(t-1);
printf("%d\n", ans);
return 0;
}
③n堆石子环形排列状态方程:dp[i][j]=min(dp[i][k]+dp[(i+k+1)%n][j-k-1]+sum[i+j]-sum[i-1]
(2).括号匹配 存入字符数组a[],完了以后遍历数组.....then如果为左括号,则将其入栈,如果为右括号那就将其与栈顶元素比较,若配对了一对括号,则将栈顶元素出栈,若不匹配,则退出算法并返回不匹配结果。遍历完数组后栈空,说明括号全部配对,否则,说明缺少左括号或右括号。
每次合并最小的两堆就好了SDNUOJ1013石子合并简化版
[cpp] view plain copy#include<cstdio>
#include<algorithm>
#include<iostream>
#include<cstring>
using namespace std;
int main()
{
int n;
int sum;
int x[10010];
while(cin>>n&&n != 0)
{
sum = 0;
memset(x, 0, sizeof(x));
for(int i = 0; i < n; i++)
cin>>x[i];
sort(x, x+n);
for(int i = n-1; i > 0; i--)
{
x[i-1] = x[i-1] + x[i];
sum=(sum % 1000000007 + x[i-1] % 1000000007) % 1000000007;
}
cout<<sum<<endl;
}
return 0;
}
②.n堆石子直线排列,每堆有a[i]个,每次合并相邻两堆,需要体力为相邻两堆石子之和sum[i]是前i堆总的石子个数状态方程:dp[i][j] = min(dp[i][j], dp[i][k] + dp[k+1][j] + sum[j] - sum[i-1]);[cpp] view plain copy
[cpp] view plain copy/*for(int i = 0; i < n; i++)
dp[i][i]=0;*/
for(int t = 1; t < n; t++)
{
for(int i = 0; i < n-t; i++)
{
int j = i + t;
dp[i][j] = inf;
for(int k = i; k < j; k++)
dp[i][j] = min(dp[i][j], dp[i][k]+dp[k+1][j] + sum[j] - sum[i-1]);
}
}
SDNUOJ1045石子合并1朴素算法[cpp] view plain copy#include<cstdio>
#include<iostream>
using namespace std;
#define inf 0xffffff
int main()
{
int n;
int a[210];
int sum[210];
int dp[210][210];
scanf("%d",&n);
for(int i = 0; i < n; i++)
{
scanf("%d", &a[i]);
sum[i]=sum[i-1] + a[i];
}
for(int i = 0; i < n; i++)
dp[i][i] = 0;
for(int t = 1; t < n; t++)
{
for(int i = 0; i < n-t; i++)
{
int j = i + t;
dp[i][j] = inf;
for(int k = i; k < j; k++)
dp[i][j] = min(dp[i][j], dp[i][k]+dp[k+1][j] + sum[j] - sum[i-1]);
}
}
printf("%d", dp[0][n-1]);
return 0;
}
这个时间复杂度......o(n^3)四边形不等式优化[cpp] view plain copy/*for(int i=1; i<=n; i++)
{
dp[i][i] = 0;
p[i][i] = i;
} */
for(int len=1; len<n; len++)
{
for(int i=1; i+len<=n; i++)
{
int end = i+len;
int tmp = INF;
int k = 0;
for(int j=p[i][end-1]; j<=p[i+1][end]; j++)
{
if(dp[i][j] + dp[j+1][end] + sum[end] - sum[i-1] < tmp)
{
tmp = dp[i][j] + dp[j+1][end] + sum[end] - sum[i-1];
k = j; //找到令dp最小的k记下来
}
}
dp[i][end] = tmp;
p[i][end] = k;
}
}
ac代码[cpp] view plain copy#include<cstdio>
#include<iostream>
using namespace std;
#define inf 0xffffff
int main()
{
int n;
int a[210];
int sum[210];
int dp[210][210];
int p[210][210];
scanf("%d",&n);
for(int i = 1; i <= n; i++)
{
scanf("%d", &a[i]);
sum[i]=sum[i-1] + a[i];
}
for(int i=1; i<=n; i++)
{
dp[i][i] = 0;
p[i][i] = i;
}
for(int len=1; len<n; len++)
{
for(int i=1; i+len<=n; i++)
{
int end = i+len;
int tmp = inf;
int k = 0;
for(int j=p[i][end-1]; j<=p[i+1][end]; j++)
{
if(dp[i][j] + dp[j+1][end] + sum[end] - sum[i-1] < tmp)
{
tmp = dp[i][j] + dp[j+1][end] + sum[end] - sum[i-1];
k = j;
}
}
dp[i][end] = tmp;
p[i][end] = k;
}
}
printf("%d", dp[1]
);
return 0;
}
时间复杂度大概为o(n^2)了完了以后GarsiaWachs算法
哇咔咔妙哇存stone[ ]数组,从左往右,找一个k满足stone[k-1] <= stone[k+1],完了以后合并stone[k]和stone[k-1],再从当前位置开始向左找最大的j,使其满足stone[j] > stone[k]+stone[k-1],插到j的后面。重复,直到只剩下一堆石子......假设stone[-1]和stone
是正无穷的
ac代码[cpp] view plain copy#include <cstdio>
#include <iostream>
using namespace std;
int stone[205];
int n,t,ans;
void combine(int k)
{
int tmp = stone[k] + stone[k-1];
ans += tmp;
for(int i = k; i < t-1; i++)
stone[i] = stone[i+1];
t--;
int j = 0;
for(j = k - 1; j > 0 && stone[j-1] < tmp; j--)
stone[j] = stone[j-1];
stone[j] = tmp;
while(j >= 2 && stone[j] >= stone[j-2])
{
int d = t - j;
combine(j-1);
j = t - d;
}
}
int main()
{
scanf("%d", &n);
for(int i = 0; i < n; i++)
{
scanf("%d", stone + i);
}
t = 1;
ans = 0;
for(int i = 1; i < n; i++)
{
stone[t++] = stone[i];
while(t >= 3 && stone[t-3] <= stone[t-1])
combine(t-2);
}
while(t > 1) combine(t-1);
printf("%d\n", ans);
return 0;
}
③n堆石子环形排列状态方程:dp[i][j]=min(dp[i][k]+dp[(i+k+1)%n][j-k-1]+sum[i+j]-sum[i-1]
(2).括号匹配 存入字符数组a[],完了以后遍历数组.....then如果为左括号,则将其入栈,如果为右括号那就将其与栈顶元素比较,若配对了一对括号,则将栈顶元素出栈,若不匹配,则退出算法并返回不匹配结果。遍历完数组后栈空,说明括号全部配对,否则,说明缺少左括号或右括号。
相关文章推荐
- 【区间DP】NYOJ 737石子合并+POJ 2955 Brackets(括号匹配)+NYOJ 15 括号匹配(二)
- 区间DP问题(矩阵连乘,石子合并,括号匹配)
- 区间dp模型(石子归并,括号匹配,整数划分)
- 区间dp模型(石子归并,括号匹配,整数划分)入门经典三道题
- 区间dp基础(石子归并,括号匹配,整数划分。。。)
- 区间dp模型(石子归并,括号匹配,整数划分)
- 区间dp模型(石子归并,括号匹配,整数划分)
- 区间DP:POJ 2955括号匹配 + NYOJ 737 石子归并(一) + No.312 Burst Balloons
- 括号匹配(二)NYOJ15(简单区间dp)
- 区间dp模型之括号匹配打印路径 poj(1141)
- 石子合并与区间dp
- 括号匹配 区间DP (经典)
- POJ 2955 Brackets 区间DP 最大括号匹配
- 区间DP的详细解析(石子合并)
- 石子合并(区间dp)
- NYOJ 括号匹配(二) 区间DP
- NYOJ737 石子合并(一)(区间dp,详细)
- nyoj 737 石子合并 经典区间 dp
- nyoj 15 括号匹配(二)(区间DP)
- nyoj 737 石子合并(一)(区间DP)