区间dp 小小结
来源:互联网 发布:传统武术实战 知乎 编辑:程序博客网 时间:2024/06/05 23:51
A - Halloween Costumes LightOJ - 1422
题意:有n个万圣节晚会,晚会按顺序参加,每个晚会都要求穿要求的衣服。衣服上面可以套衣服。问穿衣服的最少次数
分析:解释一下样例,1 2 1 2(4个晚会的衣服),可以先穿1,然后穿2,脱2,穿2。所以穿衣服的次数是3次。
区间dp。
状态 : dp[i][j]:第i个晚会到第j个晚会穿衣服的最少次数。
开始是这样想的,假设i的衣服在k的位置重复利用了那就是
for(int k=i+1;k<=j-1;k++)
if(a[i]==a[k])
dp[i][j]=min(dp[i][j],dp[i+1][k]+dp[k+1][j]);
但是wa了,因为对于dp[i][j]来说,我们只考虑i的重复出现,但是j可能也是重复出现的呀
然后加一个
for(int k=i+1;k<=j-1;k++)
if(a[j]==a[k])
dp[i][j]=min(dp[i][j],dp[i][k]+dp[k+1][j-1]);
就过了。其实这两个可以合成一个
for(int k=i;k<=j-1;k++)
dp[i][j]=min(dp[i][j],dp[i][k]+dp[k+1][j]);
#include <iostream>#include <cstdio>#include <algorithm>#include <cmath>#include <cstring>#include <vector>using namespace std;#define inf 0x3f3f3f3f#define ll long long#define mem(a,b) memset(a,b,sizeof(a))inline int MIN(int a,int b) {return a<b?a:b;}inline int MAX(int a,int b) {return a>b?a:b;}const int maxn = 105;int a[maxn],dp[maxn][maxn];int main(){ int T,n,case1=1; scanf("%d",&T); while(T--) { mem(dp,inf); scanf("%d",&n); for(int i=1;i<=n;i++) scanf("%d",&a[i]); for(int len=1;len<=n;len++) { for(int i=1;i<=n;i++) { int j=i+len-1; if(j>n) break; if(len==1) {dp[i][j]=1;continue;} else if(a[j-1]==a[j]) dp[i][j]=min(dp[i][j],dp[i][j-1]); if(a[i]==a[j]) {dp[i][j]=min(dp[i][j],dp[i][j-1]);} for(int k=i;k<=j-1;k++) dp[i][j]=min(dp[i][j],dp[i][k]+dp[k+1][j]); } } printf("Case %d: %d\n",case1++,dp[1][n]); } return 0;}/*271 2 1 1 3 2 1*/
B - Brackets POJ - 2955
题意:括号匹配。给你一个字符串,有四种字符’(‘,’)’,’[‘,’]’,(),[]这样算一对,问这串字符串中最多有多少匹配字符。
什么是匹配,就是对里面是对。比如([]),有四个匹配字符,([)],这样只有两个匹配字符。
分析 :
状态 dp[i][j] :从下标i到j的最大匹配字符的数量
状态转移:dp[i][j]=max(dp[i][j],dp[i][k]+dp[k+1][j]);
#include <iostream>#include <cstdio>#include <algorithm>#include <cmath>#include <cstring>#include <vector>using namespace std;#define inf 0x3f3f3f3f#define ll long long#define mem(a,b) memset(a,b,sizeof(a))inline int MIN(int a,int b) {return a<b?a:b;}inline int MAX(int a,int b) {return a>b?a:b;}const int maxn = 105;char s[maxn];int dp[maxn][maxn];int main(){ while(scanf("%s",s)!=EOF) { if(s[0]=='e') break; mem(dp,0); int slen=strlen(s); for(int len=2;len<=slen;len++) { for(int i=0;i<slen;i++) { int j=i+len-1; if(j>=slen) break; else if((s[i]=='('&&s[j]==')')||(s[i]=='['&&s[j]==']')) {if(len==2) dp[i][j]=2;else dp[i][j]=max(dp[i][j],dp[i+1][j-1]+2);} for(int k=i;k<=j-1;k++) dp[i][j]=max(dp[i][j],dp[i][k]+dp[k+1][j]); } } printf("%d\n",dp[0][slen-1]); } return 0;}/*()()()()*/
C - Coloring Brackets CodeForces - 149D
题意:给一串匹配字符串,字符只有’(’ ‘)’ ,所以字符的对应是唯一的。给这些字符涂色,有下面几点要求
1.有两种颜色,红色,蓝色。开始的括号是无色的。
2. 每对括号,只能有一个括号被涂色(红或蓝)
3.相邻两个字符不能涂相同颜色,可以同时不涂色。
问一共有多少种涂色方案,方案数mod 1e9+7
分析;首先,模拟一下栈,记录一下字符的对应。然后区间dp
dp[l][r][i][j]:下标从l到r,l颜色为i,r颜色为j的方案数
#include <algorithm>#include <cmath>#include <cstdio>#include <cstring>#include <iostream>#include <vector>using namespace std;#define ll long long#define mem(a,b) memset(a,b,sizeof(a))const int maxn = 705,inf=1e9+7;char s[maxn];ll dp[maxn][maxn][5][5];int mat[maxn],tem[maxn];void getmat(int len){ int p=0; for(int i=0;i<len;i++) { if(s[i]=='(') tem[p++]=i; else { mat[i]=tem[p-1]; mat[tem[p-1]]=i; p--; } }}void dfs(int l,int r){ if(r-l==1) { dp[l][r][0][1]=1; dp[l][r][0][2]=1; dp[l][r][1][0]=1; dp[l][r][2][0]=1; return; } if(mat[l]==r) { dfs(l+1,r-1); for(int i=0;i<3;i++) { for(int j=0;j<3;j++) { if(j!=1) dp[l][r][0][1]=(dp[l][r][0][1]+dp[l+1][r-1][i][j])%inf; if(j!=2) dp[l][r][0][2]=(dp[l][r][0][2]+dp[l+1][r-1][i][j])%inf; if(i!=1) dp[l][r][1][0]=(dp[l][r][1][0]+dp[l+1][r-1][i][j])%inf; if(i!=2) dp[l][r][2][0]=(dp[l][r][2][0]+dp[l+1][r-1][i][j])%inf; } } } else { int p=mat[l]; dfs(l,p); dfs(p+1,r); for(int i=0;i<3;i++) { for(int j=0;j<3;j++) { for(int k=0;k<3;k++) { for(int h=0;h<3;h++) { if(k==1&&h==1) continue; if(k==2&&h==2) continue; dp[l][r][i][j]=(dp[l][r][i][j]+dp[l][p][i][k]*dp[p+1][r][h][j]%inf)%inf; } } } } }}int main(){ while(scanf("%s",s)!=EOF) { mem(dp,0);mem(mat,0); int slen=strlen(s); getmat(slen); dfs(0,slen-1); ll ans=0; for(int i=0;i<3;i++) for(int j=0;j<3;j++) ans=(ans+dp[0][slen-1][i][j])%inf; printf("%lld\n",ans); } return 0;}/*(())(()())*/
D - Multiplication Puzzle POJ - 1651
题意:给一串数字,要将这些数字拿走(除了左右两边的数),每拿走一个数,都会有一个价值 ,比如 a1,a2,a3,拿走a2的价值为a1*a2*a3,问拿走这些数字最少的价值之和
分析:
dp[i][j]:拿走i,j之间的数最少的价值之和
dp[i][j]=min(dp[i][j],dp[i][k]+dp[k][j]+a[k]*a[i]*a[j]);
#include <algorithm>#include <cmath>#include <cstdio>#include <cstring>#include <iostream>#include <vector>using namespace std;#define ll long long#define mem(a,b) memset(a,b,sizeof(a))const int maxn = 105,inf=0x3f3f3f3f;ll dp[maxn][maxn],a[maxn];int main(){ int n; scanf("%d",&n); mem(dp,inf); for(int i=1;i<=n;i++) scanf("%d",&a[i]); for(int len=1;len<=n;len++) { for(int i=1;i<=n;i++) { int j=i+len-1; if(j>n) break; if(len<=2)dp[i][j]=0; for(int k=i+1;k<j;k++) dp[i][j]=min(dp[i][j],dp[i][k]+dp[k][j]+a[k]*a[i]*a[j]); } } printf("%lld\n",dp[1][n]); return 0;}/*610 1 50 50 20 5*/
E - You Are the One HDU - 4283
题意:有n个人上台,每个人都有一个单位怒气值,如果第k个上台的人,单位怒气值为q,那么他的怒气值为(k-1)*q。这n个人排好队准备上台了,舞台旁边有一个栈,我们可以通过这个栈来改变,他们上台顺序。问这n个人上台的怒气值之和最小为多少。
分析:
dp[i][j]:表示第i个人到第j个人,最小的怒气和
dp[i][j]=min(dp[i][j],dp[i+1][k]+dp[k+1][j]-sum[k]+sum[i]+a[i]*(k-1));
表示第i个人,第k个上场。
#include <algorithm>#include <cmath>#include <cstdio>#include <cstring>#include <iostream>#include <vector>using namespace std;#define ll long long#define mem(a,b) memset(a,b,sizeof(a))const int maxn = 105,inf=0x3f3f3f3f;ll dp[maxn][maxn],a[maxn],sum[maxn];int main(){ int T,n,case1=1;; scanf("%d",&T); while(T--) { scanf("%d",&n); mem(dp,inf);mem(sum,0); for(int i=1;i<=n;i++) { scanf("%d",&a[i]); sum[i]=sum[i-1]+a[i]; } for(int len=1;len<=n;len++) { for(int i=1;i<=n;i++) { int j=i+len-1; if(j>n) break; if(len==1) dp[i][j]=a[i]*(i-1); else if(len==2) {dp[i][j]=min(dp[i][j],min(dp[i][i]+dp[j][j],dp[j][j]-a[j]+dp[i][i]+a[i]));} else { for(int k=i+1;k<j;k++) dp[i][j]=min(dp[i][j],dp[i+1][k]+dp[k+1][j]-sum[k]+sum[i]+a[i]*(k-1)); dp[i][j]=min(dp[i][j],min(dp[i][i]+dp[i+1][j],dp[i+1][j]-sum[j]+sum[i]+a[i]*(j-1))); } } } printf("Case #%d: %d\n",case1++,dp[1][n]); } return 0;}
F - String painter HDU - 2476
题意:给两个等长的字符串a,b。有一个操作可以将一段区间的字符全都变成一种任意字符。想将a字符串转化成b字符串,问最小操作次数。
分析:开始想直接将a转化成b的,发现对一个区间的改变两个字符串很难进行判断,转化。。
然后dalao们的做法是。
先将空字符串转化成b的操作数区间dp,然后借助这个dp来得出a的转化。
#include <algorithm>#include <cmath>#include <cstdio>#include <cstring>#include <iostream>#include <vector>using namespace std;#define ll long long#define mem(a,b) memset(a,b,sizeof(a))const int maxn = 105,inf=0x3f3f3f3f;int dp[maxn][maxn],ans[maxn];char a[maxn],b[maxn];int main(){ while(scanf("%s",a)!=EOF) { scanf("%s",b); mem(dp,inf);mem(ans,inf); int slen=strlen(a); for(int len=1;len<=slen;len++) { for(int i=0;i<slen;i++) { int j=i+len-1; if(len==1) dp[i][j]=1; else if(b[i]==b[j]) {if(len==2) dp[i][j]=1;else dp[i][j]=min(dp[i][j],min(dp[i+1][j],dp[i][j-1]));} for(int k=i;k<j;k++) dp[i][j]=min(dp[i][j],dp[i][k]+dp[k+1][j]); } } ans[0]=(a[0]==b[0]?0:1); for(int i=1;i<slen;i++) { ans[i]=dp[0][i]; if(b[i]==a[i]) ans[i]=min(ans[i],ans[i-1]); for(int k=0;k<i;k++) ans[i]=min(ans[i],ans[k]+dp[k+1][i]); } printf("%d\n",ans[slen-1]); } return 0;}/*zzzzzfzzzzzabcdefedcbaababababababcdcdcdcdcdcd*/
- 区间dp 小小结
- 区间dp小结
- 区间DP小结
- 区间dp小结
- 区间dp小结
- 区间dp小结
- 区间dp小练
- 树形DP<小小结>
- 区间DP小结(附经典例题)
- 小胖的疑惑 【整数划分 区间DP】
- lanqiao 小白算法练习 合并石子 区间dp
- 区间DP
- 区间DP
- 区间DP
- 区间DP
- ##区间dp##
- 区间dp
- 区间DP
- Vue的异步组件
- 利用OpenGL实现IOS上VR全景图
- Faster-RCNN训练问题解决
- mysql-锁(lock)
- 点阵屏
- 区间dp 小小结
- mysql查询一个表的数据插入另一个表
- 独立按键和矩阵按键
- Python TCP客户端和服务器端通信
- 2017年10月12日 第三次总结
- Spring实战笔记——Profile详解
- MySQL利用自定义函数和存储过程创建海量表,并使用索引优化
- There was a problem communicating with the PayPal servers. Please try again
- springMVC参数绑定失败的原因有以下2种