一.区间dp
1.实现思路
区间DP主要是把一个大区间拆分成几个小区间,先求小区间的最优值,然后合并起来求大区间的最优值
2.一般区间DP实现代码
memset(dp, 0x3f, sizeof(dp));
for (int i = 1; i <= n; i++) //区间长度为1的初始化
dp[i][i] = 0;
for (int len = 2; len <= n; len++) //枚举区间长度
{
for (int i = 1, j = len; j <= n; i++, j++) //区间[i,j]
{
//DP方程实现
}
}
3.例题
题目1:
给出一个字符串,问该字符串中括号的最大的匹配是多少()为一对括号的匹配,[]为一对括号的匹配。
思路:
区间DP
dp[i][j]表示i-j这个区间中括号的最大匹配数,可知对于每一个区间来说,初值为如果s[i] s[j]恰好可以匹配,那么dp[i][j]=dp[i+1][j-1]+2,如果不匹配,那么dp[i][j]=dp[i+1][j-1];
然后遍历区间断点K,求最大值。
主要实现代码:
memset(dp,0,sizeof(dp));
int n=strlen(s);
for(int len=1;len<=n;len++)
{
for(int l=0;l+len<n;l++)
{
int r=l+len;
if((s[l]=='('&&s[r]==')')||(s[l]=='['&&s[r]==']'))
dp[l][r]=dp[l+1][r-1]+2;
for(int k=l;k<r;k++)
dp[l][r]=max(dp[l][r],dp[l][k]+dp[k+1][r]);
}
}
printf("%d\n",dp[0][n-1]);
题目2:
给出一个长度为n的序列,删除一些数,每次删除一个数a【i】要付出a【i-1】* a【i】 * a【i+1】的代价,问要删除到只剩左右两个元素最少需要付出多少代价。
思路:
区间DP,L和R表示在区间L到R内,除了左边界L和右边界R不删除,删除中间所有元素所需要的最小代价。
DP【i】【j】即表示区间边界。其中两两相邻的数中间没有数可删,即该区间内花费初始化为0。这样从最小区间长度2开始,统计3个数存在时的最小花费。这样平移这段区间,求出所有该长度的花费,求得小区间后即可求更大的区间,这样不断递推下去。最终得到区间长度为n的整个序列的最小花费。
主要实现代码:
for(int i=2; i<=n; i++)
for(int j=1; j+i<=n; j++)
{
dp[j][j+i]=1e12;
for(int k=j+1; k<j+i; k++)///在一个区间内选择一个k值,这个k值和左右边界相乘,意思是删除k,并且从边界到k这两段区间优先被删掉,求和后取一个花费最小值
dp[j][j+i]=min(dp[j][j+i],a[j]*a[k]*a[j+i]+dp[j][k]+dp[k][j+i]);
// printf("dp[%d][%d] = %lld\n",j,j+i,dp[j][j+i]);
}
printf("%lld\n",dp[1][n]);///最后因为只留下第一个值和最后一个值,因此这段区间内所有值被删去的最优解即answer
题目3:
给你n天需要穿的衣服的样式,每次可以套着穿衣服,脱掉的衣服就不能再用了(可以再穿,但算cost),问至少要带多少条衣服才能参加所有宴会。
思路:
dp[i][j]表示i~j天所需的最小数量。
考虑第j天穿不穿,如果穿的话那么 dp[i][j]=dp[i][j-1]+1;
如果不穿的话,那么需要有一个 k (i<=k<j),第j天和第k天穿的衣服相同,将k+1~j-1衣服套着穿后全部脱掉,那么
dp[i][j]=dp[i][k]+dp[k+1][j-1];
主要实现代码:
for(int i = n ; i >= 1; --i)
for(int j = i ; j <= n ;++j)
{
dp[i][j] = dp[i+1][j] + 1;
for(int k = i+1 ; k <= j ; ++k)
{
if(num[k] == num[i])dp[i][j] = min(dp[i][j],dp[i+1][k-1] + dp[k][j]);
}
}
printf("Case %d: %d\n",++ca,dp[1][n]);
二.vector的复习总结
1.传参不要忘记&
vector作为函数的参数或者返回值时,需要注意它的写法:
double Distance(vector<int>&a, vector<int>&b) 其中的“&”绝对不能少!!!
2.vector闲碎用法总结
使用迭代器访问元素:
vector<int>::iterator it;
for(it=vec.begin();it!=vec.end();it++)
cout<<*it<<endl;
插入元素: vec.insert(vec.begin()+i,a);在第i+1个元素前面插入a;
删除元素: vec.erase(vec.begin()+2);删除第3个元素
vec.erase(vec.begin()+i,vec.end()+j);删除区间[i,j-1];区间从0开始
向量大小:vec.size();
清空:vec.clear();
3.
typedef struct rect
{
int id;
int length;
int width;
//对于向量元素是结构体的,可在结构体内部定义比较函数,下面按照id,length,width升序排序。
bool operator< (const rect &a) const
{
if(id!=a.id)
return id<a.id;
else
{
if(length!=a.length)
return length<a.length;
else
return width<a.width;
}
}
}Rect;
4.两种写法的区别
c++中如果用typedef的话,会造成区别:
struct Student
{
int a;
}stu1;//stu1是一个变量
typedef struct Student2
{
int a;
}stu2;//stu2是一个结构体类型
使用时可以直接访问stu1.a
但是stu2则必须先 stu2 s2;
然后 s2.a=10;
5.定义结构体类型的vector容器:
定义结构体类型的vector容器:
struct Student
{
int age;
string name;
};//这里不给他声明变量名vector <Student>stu;
后面用容器的话写个循环:
for(int i = 0;i<stu.size();i++)
{
cout<<stu.at(i).age;
cout<<stu.at(i).name;
}
添加容器的话:
Student student1 = {20,“小明”};
Student student2 = {20,“小红”};
stu.push_back(student1);
stu.push_back(student2);