zoukankan      html  css  js  c++  java
  • [笔记]: 区间dp 2017-06-12 08:13 44人阅读 评论(0) 收藏

    区间dp

    对于给出的区间 l r ,f[l][r]记录其最值

    那么 f[l][r]=f[l][k]+f[k+1][r]+f[k][k];

    左半部分+右半部分+切k这一段所带来的收益

    例题 codevs1048石子归并

    //http://codevs.cn/problem/1048/
    #include<iostream>
    #include<cstdio>
    #include<cstdlib>
    #include<cstring>
    #include<algorithm>
    #include<cmath>
    #define N 205
    #define inf 9999999
    using namespace std;
    int f[N][N],sum[N],n,w[N];
    int main(){
    	scanf("%d",&n);
    	for(int i=1;i<=n;i++) {
    		scanf("%d",&w[i]);sum[i]=sum[i-1]+w[i];
    	}
    	for(int j=2;j<=n;j++){
    		for(int i=j-1;i>=1;i--){ 
                f[i][j]=inf;
    			for(int k=i;k<j;k++)
    			 	f[i][j]=min(f[i][k]+f[k+1][j]+sum[j]-sum[i-1],f[i][j]);
    		}
    	}
    	printf("%d",f[1][n]);
    	return 0;
    }
    

    vijos1347 乘积最大

    #include<iostream>
    #include<cstdio>
    #include<cstdlib>
    #include<cstring>
    #include<algorithm>
    #include<cmath>
    #define ll long long
    using namespace std;
    ll f[50][10];char s[50];
    ll getsum(int l,int r){
    	ll a=0;
    	for(int i=l;i<=r;i++)
    		a=a*10+s[i]-'0';
    	return a;
    }
    int main(){
    	int n,t;
    	scanf("%d%d",&n,&t);
    	scanf("%s",s+1);
    	for(int i=1;i<=n;i++){
    		f[i][0]=getsum(1,i);
    	}
    	for(int i=2;i<=n;i++){
    		for(int j=1;j<=t;j++) {
    			for(int k=1;k<=i-1;k++){
    				f[i][j]=max(f[i][j],f[k][j-1]*getsum(k+1,i));
    			}
    		}
    	}
    	printf("%lld",f[n][t]);
    	return 0;	
    } 

    noip2006能量项链

    #include<iostream>
    #include<cstdio>
    #include<cstdlib>
    #include<cstring>
    #include<algorithm>
    #include<cmath>
    #define N 202
    using namespace std;
    int f[N][N];int s[N],n,a[N],mx;
    int main(){
    	scanf("%d",&n);
    	for(int i=1;i<=n;i++)
    		scanf("%d",&s[i]);
    	for(int i=1;i<=n;i++)//变成 环 
    		s[i+n]=s[i];
    	
    	for(int len=2;len<=n;len++){
    		for(int i=1;i+len-1<=2*n;i++){
    			int j=i+len-1;
    			for(int k=i;k<j;k++)
    				f[i][j]=max(f[i][j],f[i][k]+f[k+1][j]+s[i]*s[k+1]*s[j+1]);//加上合并左右两部分的能量为 s[i]*s[k+1]*s[j+1]
    			mx=max(f[i][i+n-1],mx); 
    		}
    	}
    	printf("%d",mx);
    	return 0;
    } 

    ps 在石子归并中sum数组算前缀和

    但普通的查询连续区间最大和的时间时O(n^2)线段树和树状数组都是O(nlogn)

    有O(n)的优化程序

    //前缀和思想 但是时间复杂度从O(n^2)降到了O(n) 
    //对于确定的j i到j的连续和=sum[j]-sum[i-1] 其实就是使sum[i-1]最小 所以对于当前状态 维护最小的sum[i-1]就行了 
    #include<iostream>
    #include<cstdio>
    #include<cstdlib>
    #include<cstring>
    #include<algorithm>
    #include<cmath>
    #define N 10000
    #define inf 2147483647
    using namespace std;
    int a[N],sum[N],mn,mx;
    int main(){
    	int n;
    	scanf("%d",&n);
    	for(int i=1;i<=n;i++){
    		scanf("%d",&a[i]);sum[i]=sum[i-1]+a[i];
    	}
    	sum[0]=inf;mn=0;	
    	for(int i=1;i<=n;i++){
    		if(sum[mn]>sum[i-1]) mn=i-1;
    		mx=max(mx,sum[i]-sum[mn]);
    	}
    	printf("%d",mx);
    } 



  • 相关阅读:
    VC2005从开发MFC ActiveX ocx控件到发布到.net网站的全部过程
    【Demo 0025】注册/反注册窗体类RegisterClassEx/UnregisterClass
    《白手起家Win32SDK应用程序》(完整版+目录)
    关于初始化C++类成员
    TCP和UDP的"保护消息边界" (经典)
    (经典)tcp粘包分析
    解决TCP网络传输“粘包”问题
    无锁队列
    MFC全局函数开局——AfxGetApp解剖
    Tomcat系列之服务器的安装与配置以及各组件详解
  • 原文地址:https://www.cnblogs.com/xljxlj/p/7183618.html
Copyright © 2011-2022 走看看