您的位置:首页 > 其它

区间dp(石子合并and括号匹配)

2018-03-23 19:29 609 查看
就是把大区间划分为小区间然后取小区间的最优值处理石子合并和括号匹配(1). 石子合并①.n堆石子,每堆有a[i]个,每次合并两堆,需要体力为相邻两堆石子之和
每次合并最小的两堆就好了SDNUOJ1013石子合并简化版
[cpp] view plain copy#include<cstdio>  
#include<algorithm>  
#include<iostream>  
#include<cstring>  
using namespace std;  
int main()  
{  
    int n;  
    int sum;  
    int x[10010];  
    while(cin>>n&&n != 0)  
    {  
        sum = 0;  
        memset(x, 0, sizeof(x));  
        for(int i = 0; i < n; i++)  
            cin>>x[i];  
        sort(x, x+n);  
        for(int i = n-1; i > 0; i--)  
        {  
            x[i-1] = x[i-1] + x[i];  
            sum=(sum % 1000000007 + x[i-1] % 1000000007) % 1000000007;  
        }  
        cout<<sum<<endl;  
    }  
    return 0;  
}  

②.n堆石子直线排列,每堆有a[i]个,每次合并相邻两堆,需要体力为相邻两堆石子之和sum[i]是前i堆总的石子个数状态方程:dp[i][j] = min(dp[i][j], dp[i][k] + dp[k+1][j] + sum[j] - sum[i-1]);[cpp] view plain copy  
[cpp] view plain copy/*for(int i = 0; i < n; i++) 
    dp[i][i]=0;*/  
for(int t = 1; t < n; t++)  
    {  
        for(int i = 0; i < n-t; i++)  
        {  
            int j = i + t;  
            dp[i][j] = inf;  
            for(int k = i; k < j; k++)  
                dp[i][j] = min(dp[i][j], dp[i][k]+dp[k+1][j] + sum[j] - sum[i-1]);  
        }  
    }  
SDNUOJ1045石子合并1朴素算法[cpp] view plain copy#include<cstdio>  
#include<iostream>  
using namespace std;  
#define inf 0xffffff  
int main()  
{  
    int n;  
    int a[210];  
    int sum[210];  
    int dp[210][210];  
    scanf("%d",&n);  
    for(int i = 0; i < n; i++)  
    {  
        scanf("%d", &a[i]);  
        sum[i]=sum[i-1] + a[i];  
    }  
  
    for(int i = 0; i < n; i++)  
        dp[i][i] = 0;  
for(int t = 1; t < n; t++)  
    {  
        for(int i = 0; i < n-t; i++)  
        {  
            int j = i + t;  
            dp[i][j] = inf;  
            for(int k = i; k < j; k++)  
                dp[i][j] = min(dp[i][j], dp[i][k]+dp[k+1][j] + sum[j] - sum[i-1]);  
        }  
    }  
    printf("%d", dp[0][n-1]);  
    return 0;  
}  
这个时间复杂度......o(n^3)四边形不等式优化[cpp] view plain copy/*for(int i=1; i<=n; i++)   
    {   
        dp[i][i] = 0;   
        p[i][i] = i;   
    }  */  
    for(int len=1; len<n; len++)    
    {    
        for(int i=1; i+len<=n; i++)    
        {    
            int end = i+len;    
            int tmp = INF;    
            int k = 0;    
            for(int j=p[i][end-1]; j<=p[i+1][end]; j++)    
            {    
                if(dp[i][j] + dp[j+1][end] + sum[end] - sum[i-1] < tmp)    
                {    
                    tmp = dp[i][j] + dp[j+1][end] + sum[end] - sum[i-1];    
                    k = j;  //找到令dp最小的k记下来  
                }    
            }    
            dp[i][end] = tmp;    
            p[i][end] = k;    
        }    
    }    
ac代码[cpp] view plain copy#include<cstdio>  
#include<iostream>  
using namespace std;  
#define inf 0xffffff  
int main()  
{  
    int n;  
    int a[210];  
    int sum[210];  
    int dp[210][210];  
    int p[210][210];  
    scanf("%d",&n);  
    for(int i = 1; i <= n; i++)  
    {  
        scanf("%d", &a[i]);  
        sum[i]=sum[i-1] + a[i];  
    }  
for(int i=1; i<=n; i++)  
    {  
        dp[i][i] = 0;  
        p[i][i] = i;  
    }  
    for(int len=1; len<n; len++)  
    {  
        for(int i=1; i+len<=n; i++)  
        {  
            int end = i+len;  
            int tmp = inf;  
            int k = 0;  
            for(int j=p[i][end-1]; j<=p[i+1][end]; j++)  
            {  
                if(dp[i][j] + dp[j+1][end] + sum[end] - sum[i-1] < tmp)  
                {  
                    tmp = dp[i][j] + dp[j+1][end] + sum[end] - sum[i-1];  
                    k = j;    
                }  
            }  
            dp[i][end] = tmp;  
            p[i][end] = k;  
        }  
    }  
    printf("%d", dp[1]
);  
    return 0;  
}  
时间复杂度大概为o(n^2)了完了以后GarsiaWachs算法
哇咔咔妙哇存stone[ ]数组,从左往右,找一个k满足stone[k-1] <= stone[k+1],完了以后合并stone[k]和stone[k-1],再从当前位置开始向左找最大的j,使其满足stone[j] > stone[k]+stone[k-1],插到j的后面。重复,直到只剩下一堆石子......假设stone[-1]和stone
是正无穷的
ac代码[cpp] view plain copy#include <cstdio>  
#include <iostream>  
using namespace std;  
  
int stone[205];  
int n,t,ans;  
  
void combine(int k)  
{  
    int tmp = stone[k] + stone[k-1];  
    ans += tmp;  
    for(int i = k; i < t-1; i++)  
        stone[i] = stone[i+1];  
    t--;  
    int j = 0;  
    for(j = k - 1; j > 0 && stone[j-1] < tmp; j--)  
        stone[j] = stone[j-1];  
    stone[j] = tmp;  
    while(j >= 2 && stone[j] >= stone[j-2])  
    {  
        int d = t - j;  
        combine(j-1);  
        j = t - d;  
    }  
}  
  
int main()  
{  
    scanf("%d", &n);  
    for(int i = 0; i < n; i++)  
    {  
        scanf("%d", stone + i);  
    }  
    t = 1;  
    ans = 0;  
    for(int i = 1; i < n; i++)  
    {  
        stone[t++] = stone[i];  
        while(t >= 3 && stone[t-3] <= stone[t-1])  
            combine(t-2);  
    }  
    while(t > 1) combine(t-1);  
    printf("%d\n", ans);  
    return 0;  
}  

③n堆石子环形排列状态方程:dp[i][j]=min(dp[i][k]+dp[(i+k+1)%n][j-k-1]+sum[i+j]-sum[i-1]
(2).括号匹配  存入字符数组a[],完了以后遍历数组.....then如果为左括号,则将其入栈,如果为右括号那就将其与栈顶元素比较,若配对了一对括号,则将栈顶元素出栈,若不匹配,则退出算法并返回不匹配结果。遍历完数组后栈空,说明括号全部配对,否则,说明缺少左括号或右括号。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息