ACM之近期学习总结

一.区间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);

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值