动态规划-区间DP

1.尼克的任务

#include <stdio.h>
#include <memory.h>
#include <math.h>
#include <string>
#include <vector>
#include <set>
#include <stack>
#include <queue>
#include <algorithm>
#include <map>


#define I scanf
#define OL puts
#define O printf
#define F(a,b,c) for(a=b;a<c;a++)
#define FF(a,b) for(a=0;a<b;a++)
#define FG(a,b) for(a=b-1;a>=0;a--)
#define LEN 10010
#define MAX 1<<30
#define V vector<int>

using namespace std;

typedef struct node{
    int s,e;
}node; 

node t[LEN];
int dp[LEN];
int st[LEN];

int cmp(node a,node b){            //用于递减排序,重定义大于符号 
    return a.s>b.s;
}

int main(){
//    freopen("尼克的任务.txt","r",stdin);
    int n,k,i,j,m;
    I("%d %d",&n,&k);
    F(i,1,k+1){
        I("%d%d",&t[i].s,&t[i].e);
        st[t[i].s]++;            //记录起始时间点 
    } 
    sort(t+1,t+1+k,cmp);        //让时间结构体递减排序
    for(i=n;i>=1;i--){            //对于时间,从后往前循环 
        if(st[i]==0){            //从后往前循环的过程中,没有没有查询到起始时间点 
            dp[i]=dp[i+1]+1;     //dp数组表示 从i时刻往后的空闲时间 
        }else{                    //查询到了起始时间点 
            for(m=1;m<=k;m++){    //对所有任务进行遍历 
                if(t[m].s==i){    //遍历到的任务的其实时间点是当前时间点 
                    dp[i]=max(dp[i],dp[i+t[m].e]);
                }                //找出所有i时间开始的任务,记录他们结束时 最大的空闲时间 
            } 
        } 
    } 
    O("%d\n",dp[1]);
    return 0;
}
View Code

 


 2.括号匹配

主代码:

//对角线初始化
for(i=0;i<len;i++)
    dp[i][i]=1;
//动态规划
 for(v=1;v<len;v++){            //定义间隔
     for(i=0;i+v<len;i++){        //定义起始下标
         int j=i+v;                //定义结束下标
         dp[i][j]=MAX;
        if(cmp(str[i],str[j]))    //如果i到j的括号可以匹配
            dp[i][j]=min(dp[i][j],
                    dp[i+1][j-1]); //就对比中间的情况 :dp[i+1][j-1]
                    //(在这里我们注意到特殊情况dp[0][1],中间情况是dp[1][0], 因为dp矩阵是上三角矩阵,为0,满足定义
        for(k=i;k<j;k++){        //进行子情况剖分
            dp[i][j]=min(dp[i][j],
                         dp[i][k]+dp[k+1][j]);
        }
     }
 }

完整代码:

#include<cstdio>
#include<iostream>
#include<string.h>


#define I scanf
#define OL puts
#define O printf
#define F(a,b,c) for(a=b;a<c;a++)
#define FF(a,b) for(a=0;a<b;a++)
#define FG(a,b) for(a=b-1;a>=0;a--)
#define LEN 300
#define MAX 1<<30
#define V vector<int>

using namespace std;

int dp[LEN][LEN];

bool cmp(int a, int b){
    if( (a=='[' && b==']') || (a=='(' && b==')') ){
        return 1;
    }
    return 0;
}

int main(){
//    freopen("D:/CbWorkspace/动态规划/括号匹配.txt","r",stdin);
    int i,j,k,v,n;
    char str[LEN];
    I("%d",&n);
    while(n--){
        I("%s",str);
        int len=strlen(str);
        memset(dp,0,sizeof(dp));
        //对角线初始化
        for(i=0;i<len;i++)
            dp[i][i]=1;
        //动态规划
         for(v=1;v<len;v++){            //定义间隔
             for(i=0;i+v<len;i++){        //定义起始下标
                 int j=i+v;                //定义结束下标
                 dp[i][j]=MAX;
                if(cmp(str[i],str[j]))    //如果i到j的括号可以匹配
                    dp[i][j]=min(dp[i][j],
                            dp[i+1][j-1]); //就对比中间的情况 :dp[i+1][j-1]
                            //(在这里我们注意到特殊情况dp[0][1],中间情况是dp[1][0], 因为dp矩阵是上三角矩阵,为0,满足定义
                for(k=i;k<j;k++){        //进行子情况剖分
                    dp[i][j]=min(dp[i][j],
                                 dp[i][k]+dp[k+1][j]);
                }
             }
         }
         O("%d\n",dp[0][len-1]);
    }
    return 0;
}
View Code

dp矩阵示意:

 


 3.整数划分

递归:(类似于把m个苹果放入n个盒子)

int recursion(int m,int n){//表示把m划分成n个数 
    if(n==1||n==m){
        return 1;
    }else if(m<n){
        return 0;
    }else{    //递归原则:看成 包含 1 与 不包含 1 的两部分 
        return recursion(m-1,n-1) + //固定第一个数字 1 ,划分 m-1 为 n-1 个数 
               recursion(m-n,n);    //划分出来的 n 个数字全部减 1 , 相当于把 m-n 划分成 n 个数 
    }
}

动态规划:

 


 

4.回文字符串

获得一个字符串最长的回文子串长度:

#include <stdio.h>
#include <memory.h>
#include <math.h>
#include <cstring>
#include <vector>
#include <set>
#include <stack>
#include <queue>
#include <algorithm>
#include <map>


#define I scanf
#define OL puts
#define O printf
#define F(a,b,c) for(a=b;a<c;a++)
#define FF(a,b) for(a=0;a<b;a++)
#define FG(a,b) for(a=b-1;a>=0;a--)
#define LEN 1001
#define MAX 1<<30
#define V vector<int>

using namespace std;

int dp[LEN][LEN];

int main(){
    freopen("回文字符串.txt","r",stdin);
    int N,n,i,j,v,ans;
    I("%d",&N);
    while(N--){
        ans=1;
        char str[LEN];
        I("%s",str);
        n=strlen(str);
        memset(dp,0,sizeof(dp));
        for(i=0;i<n;i++)
            dp[i][i]=1;
        for(v=1;v<n;v++){
            for(i=0;i+v<n;i++){
                j=i+v;
                if(str[i]==str[j]){
                    dp[i][j]=dp[i+1][j-1]+2;
                    ans=max(ans,dp[i][j]) ;
                }
            }
        }
        O("%d\n",ans);
    }
    return 0;
}
View Code

题解:

#include <stdio.h>
#include <memory.h>
#include <math.h>
#include <cstring>
#include <vector>
#include <set>
#include <stack>
#include <queue>
#include <algorithm>
#include <map>


#define I scanf
#define OL puts
#define O printf
#define F(a,b,c) for(a=b;a<c;a++)
#define FF(a,b) for(a=0;a<b;a++)
#define FG(a,b) for(a=b-1;a>=0;a--)
#define LEN 1001
#define MAX 1<<30
#define V vector<int>

using namespace std;

int dp[LEN][LEN];

int main(){
//    freopen("回文字符串.txt","r",stdin);
    int N,n,i,j,v,ans,k;
    I("%d",&N);
    while(N--){
        ans=1;
        char str[LEN];
        I("%s",str);
        n=strlen(str);
        memset(dp,0,sizeof(dp));
        for(v=1;v<n;v++){
            for(i=0;i+v<n;i++){
                j=i+v;
                if(str[i]==str[j])
                    dp[i][j]=dp[i+1][j-1];
                else
                    dp[i][j]=min(dp[i+1][j],dp[i][j-1])+1;
            }
        }
        O("%d\n",dp[0][n-1]);
    }
    return 0;
}
View Code

鸣谢欧阳大佬给的状态转移方程!

 


 

posted @ 2018-02-09 10:42  TQCAI  阅读(213)  评论(0编辑  收藏  举报