今天看一一下动态规划
分四步:
1.确定状态
找到子问题(可以拿最后一步来分析)
2.找出状态转移方程
这个虽然是找规律,但是有一定难度
3.设定初始条件和边界条件,防止越界
4.确定计算顺序
由状态转移方程得出
例如:沙堆合成问题(相邻)
链接:
子问题:
dp[i][j] 可以是dp[i][i] 和 dp[i+1][j] 这种情况(此处和不代表代价代价数量)
也可以是dp[i][i+1] dp[i+2][j] 这种情况
分别列出求最小
状态转移方程
dp[i][j]=min(dp[i][j],dp[i][k]+dp[k+1][j]+sum[j]-sum[i-1]);
初始条件:自己一堆(或者说自己与自己合成代价为0)
for(i=0; i<=n; i++)
dp[i][i]=0;
边界条件:
初始的dp[i][j]为足够大
链接:
代码:
#include<iostream>
#include<set>
#include<algorithm>
#include<functional>
#define MAX 0x3f3f3f3f
using namespace std;
int dp[350][350];
int sum[350];//表示前sum[i]项代价总和
int main()
{
int n;
cin>>n;
int i,j,k;
sum[0]=0;
fill(dp[i],dp[i]+350*350,MAX);
//一维和sort类似
//fill(dp,dp+350,MAX);
for(i=1; i<=n; i++)//
{
int temp;
cin>>temp;
sum[i]=sum[i-1]+temp;
}
for(i=0; i<=n; i++)
{
dp[i][i]=0;
}
//cout<<dp[1][n];
for(i=n-1; i>=1; i--)
{
for(j=i+1; j<=n; j++)
{
for(k=i; k<=j-1; k++)
{
dp[i][j]=min(dp[i][j],dp[i][k]+dp[k+1][j]+sum[j]-sum[i-1]);//注意是i-j区间
}
}
}
cout<<dp[1][n];
return 0;
}
上面练习fill所以用了fill
如果是memset
初始化如下,不加万能头居然会报错// 忘了memset是在#include<string.h>里面了,刚刚想起来
memset(dp,0x3f,sizeof(dp));
下一题
一开始想用栈 一个一个接收string 但是又有撤销删除的操作,感觉行不通
又想用一个字符数组加一个辅助下标数组,但是感觉还是不能实现撤消操作
没想到这是一个大水题
string 在运行期最大长度是2^31-1(2147483647)
看看数据(补充:多组输入会超时……)
直接吧每一步操作完后的记事本的结果保存放stack里面就好了
……
#include<iostream>
#include<set>
#include<algorithm>
#include<functional>
#include<stack>
#include<cstdio>
#define MAX 0x3f3f3f3f
using namespace std;
//stack<string>text;
string temp;
string newtemp;
int main()
{
//记事本 直接记录每一步操作
int n;
while(cin>>n)//比scanf快
{
stack<string> mystack;
mystack.push("");
int i,j,k;
for(i=0; i<n; i++)
{
int choice;
cin>>choice;
switch(choice)
{
case 1:
//插入
cin>>temp;
//mystack.push(temp); 这里错了
mystack.push(mystack.top()+temp);
break;
case 2:
cin>>k;//
temp=mystack.top();
newtemp=temp.substr(0,temp.length()-k);//左闭右开
mystack.push(newtemp);//
break;
case 3:
cin>>k;//忘记输入k了
temp=mystack.top();
cout<<temp[k-1]<<endl;
break;
case 4:
mystack.pop();
break;
}
}
}
return 0;
}