zoukankan      html  css  js  c++  java
  • HDU 3506 Monkey Party(区间dp)

    思路:

    1.这题是经典区间dp问题“石子合并”的一个变型;
    2.“石子合并”是没有围成环的情况,设dp[i][j]为将从ij的石子合成一堆的最小花费(本题即是ij所有猴子认识的花费的时间),则有递推dp[i][j]=min(dp[i][j],d[i][k]+dp[k+1][j]+sum(i,j))其中sum(i,j)ij所有石子的总数目,ki遍历到j-1
    3.这种算法的时间复杂度为O(n3)O(n^3),显然有些高,我们可以采用一个数组rcd[i][j]记录遍历ij时的最优的k,那么我们稍微推演一下就可以得知我们每次遍历让krcd[i][j-1]遍历到rcd[i+1][j]即可,但是注意要初始化所有的i<=nrcd[i][i]=i,此时时间复杂度只略大于O(n2)O(n^2)
    4.既然这题是环,我们将区间拓展一下,将[1,n-1]区间镜像到n的右边,最后选取花费最小的长度为n的连续区间即可;
    (PS:我还有一个想法就是每次遍历一遍数组,选取和最小的相邻猴子,然后用这个和替换这两个猴子,继续遍历,直到只剩一个猴子,这个时间复杂度是O(n2)O(n^2),这个有空再去实现了orz)

    代码:

    #include<iostream>
    #include<algorithm>
    using namespace std;
    const int INF=1<<30;
    const int MAX_N=2005;
    int n,m[MAX_N],sum[MAX_N],dp[MAX_N][MAX_N],rcd[MAX_N][MAX_N];
    void solve(){
    	int N=2*n-1;
    	for(int len=1;len<n;len++)
    		for(int i=1;i<=N-len;i++){
    			int j=i+len;
    			dp[i][j]=INF;
    			for(int k=rcd[i][j-1];k<=rcd[i+1][j];k++)
    				if(dp[i][k]+dp[k+1][j]+sum[j]-sum[i-1]<dp[i][j]){
    					dp[i][j]=dp[i][k]+dp[k+1][j]+sum[j]-sum[i-1];
    					rcd[i][j]=k;
    				}
    		}
    	int ans=dp[1][n];
    	for(int i=2;i<=n;i++) ans=min(ans,dp[i][i+n-1]);
    	cout<<ans<<'
    ';
    }
    void clear(){
    	for(int i=0;i<=2*n;i++){
    		dp[i][i]=0; rcd[i][i]=i;
    		for(int j=i+1;j<=2*n;j++)
    			dp[i][j]=dp[j][i]=rcd[i][j]=rcd[j][i]=0;
    	}
    }
    int main(){
    	while(cin>>n){
    		for(int i=1;i<=n;i++) cin>>m[i],sum[i]=sum[i-1]+m[i];
    		for(int i=1;i<n;i++) sum[n+i]=sum[n+i-1]+m[i];
    		clear(); solve();
    	}
    	return 0;
    }
    
  • 相关阅读:
    Retina屏的移动设备如何实现真正1px的线
    使用Karma、Mocha实现vue单元测试
    ios中非ARC项目中引用ARC文件
    ios中Pldatabase的用法(4)
    ios中Pldatabase的用法(3)
    ios中Pldatabase的用法(2)
    ios中修改数字键盘
    asyncsocket的用法
    ios中Pldatabase的用法
    ios中打包
  • 原文地址:https://www.cnblogs.com/yuhan-blog/p/12308784.html
Copyright © 2011-2022 走看看