StoneMerge

今天搞了一天石子合并

几个版本

直接循环数组,每次O(n^3), 总时间O(n^4),复杂度太高了

#include <cstdio>  
#include <algorithm>  
using namespace std;  
int dp[1000][1000];  
int a[1000],n;  
int stonemax()  
{  
    for(int i=0;i<=n-1;i++)  
        dp[i][i]=0;  
    for(int len=2;len<=n;len++)  
    {  
        for(int i=0;i<n;i++)  
        {  
            int j=i+len-1;  
            if(j>=n)  
                break;  
            //int maxn=0,minn=0x7fffffff;  
            int sum=0;for(int l=i;l<=j;l++)sum+=a[l];  
            int maxn=dp[i][i]+dp[i+1][j]+sum;  
            for(int k=i+1;k<=j-1;k++)  
            {  
                maxn=max(maxn,dp[i][k]+dp[k+1][j]+sum);  
            }  
            dp[i][j]=maxn;  
        }  
    }  
    return dp[0][n-1];  
}  

int stonemin()  
{  
    for(int i=0;i<=n-1;i++)  
        dp[i][i]=0;  
    for(int len=2;len<=n;len++)  
    {  
        for(int i=0;i<n;i++)  
        {  
            int j=i+len-1;  
            if(j>=n)  
                break;  
            //int maxn=0,minn=0x7fffffff;  
            int sum=0;for(int l=i;l<=j;l++)sum+=a[l];  
            int minn=dp[i][i]+dp[i+1][j]+sum;  
            for(int k=i+1;k<=j-1;k++)  
            {  
                minn=min(minn,dp[i][k]+dp[k+1][j]+sum);  
            }  
            dp[i][j]=minn;  
        }  
    }  
    return dp[0][n-1];  
}  

int main()  
{  
    freopen("in.txt","r",stdin);  
    while(scanf("%d",&n)!=EOF)  
    {  
        for(int i=0;i<n;i++)  
            scanf("%d",&a[i]);  
        int tmp,maxn=stonemax(),minn=stonemin();  
        for(int loop=1;loop<n;loop++)  
        {  
            tmp=a[0];  
            for(int i=0;i<n-1;i++)  
                a[i]=a[i+1];  
            a[n-1]=tmp;  
            maxn=max(maxn,stonemax());  
            minn=min(minn,stonemin());  
        }  
        printf("%d %d\n",minn,maxn);  
    }  
}

扩展数组,然后DP状态扩大,空间扩了一倍,编程复杂度后面的低,时间O(n^3)
然后一直出了一个问题,就是i没有扩展到0-2n-1, 因为后面的子问题状态可能起点会 n-2n-1的范围里,一直都没有想到这个点。这里还要感谢瞿神

#include <cstdio>
#include <algorithm>
#include <iostream>
using namespace std;
int dp[1000][1000];
int a[1000],n;
int stonemax()
{
    for(int i=0; i<=n-1; i++)
        dp[i] [i] =0;
    for(int len=2; len<=n; len++)
    {
        for(int i=0; i<n; i++)
        {
            int j=i+len-1;
            if(j>=n)
                break;
            int sum=0;
            for(int l=i; l<=j; l++)sum+=a[l] ;
            int maxn=dp[i] [i] +dp[i+1][j] +sum;
            for(int k=i+1; k<=j-1; k++)
            {
                maxn=max(maxn,dp[i] [k] +dp[k+1][j] +sum);
            }
            dp[i] [j] =maxn;
        }
    }
    return dp[0][n-1];
}
int stonemin()
{
    for(int i=0; i<=n-1; i++)
        dp[i] [i] =0;
    for(int len=2; len<=n; len++)
    {
        for(int i=0; i<n; i++)
        {
            int j=i+len-1;
            if(j>=n)
                break;
            int sum=0;
            for(int l=i; l<=j; l++)sum+=a[l] ;
            int minn=dp[i] [i] +dp[i+1][j] +sum;
            for(int k=i+1; k<=j-1; k++)
            {
                minn=min(minn,dp[i] [k] +dp[k+1][j] +sum);
            }
            dp[i] [j] =minn;
        }
    }
    return dp[0][n-1];
}
int stonemax_mod()
{
    for(int i=0; i<=n-1; i++)
        dp[i] [i] =0;
    for(int len=2; len<=n; len++)
    {
        for(int i=0; i<=n-1; i++)
        {
            int j=(i+len-1)%n;
            int sum=0;
            if(i<j)
            {
                for(int l=i; l<=j; l++)sum+=a[l] ;
            }
            else
            {
                for(int l=i; l<=n-1; l++)sum+=a[l] ;
                for(int l=0; l<=j; l++)sum+=a[l] ;
            }
            int maxn=0;
            if(i<j)
            {
                for(int k=i; k<=j-1; k++)
                    maxn=max(maxn,dp[i] [k] +dp[k+1][j] +sum);
            }
            else
            {
                for(int k=i; i<=n-1; i++)
                    maxn=max(maxn,dp[i] [k] +dp[k+1][j] +sum);
                for(int k=0; k<=j-1; k++)
                    maxn=max(maxn,dp[i] [k] +dp[k+1][j] +sum);
            }
            dp[i] [j] =maxn;
        }
    }
    int maxn=0;
    for(int i=0; i<=n-1; i++)
        maxn=max(maxn,dp[i] [(i-1+n)%n]);
    return maxn;
}
int stonemax_extendarray()
{
    for(int i=0; i<=n-1; i++)
        dp[i] [i] =0,a[n+i]=a[i] ;
    int maxs=0;
    for(int len=2; len<=n; len++)
    {
        for(int i=0; i<2*n; i++)
        {
            int j=i+len-1;
            if(j>=2*n) break;
            int sum=0;
            for(int l=i; l<=j; l++)sum+=a[l] ;
            int maxn=0;
            for(int k=i; k<=j-1; k++)
            {
                maxn=max(maxn,dp[i] [k] +dp[k+1][j] +sum);
            }
            dp[i] [j] =maxn;
        }
    }
    for(int i=0; i<n; i++)maxs=max(maxs,dp[i] [n-1+i]);
    return maxs;
}
int stonemin_extendarray()
{
    for(int i=0; i<=n-1; i++)
        dp[i] [i] =0,a[n+i]=a[i] ;
    int mins=0x7fffffff;
    for(int len=2; len<=n; len++)
    {
        for(int i=0; i<2*n; i++)
        {
            int j=i+len-1;
            if(j>=2*n)break;
            int sum=0;
            for(int l=i; l<=j; l++)sum+=a[l] ;
            int minn=0x7fffffff;
            for(int k=i; k<=j-1; k++)
            {
                minn=min(minn,dp[i] [k] +dp[k+1][j] +sum);
            }
            dp[i] [j] =minn;
        }
    }
    for(int i=0; i<n; i++)mins=min(mins,dp[i] [n-1+i]);
    return mins;
}
int main()
{
    //freopen("in.txt","r",stdin);
    while(scanf("%d",&n)!=EOF)
    {
        for(int i=0; i<n; i++)
            scanf("%d",&a[i] );
        int tmp,minn=stonemin_extendarray(),maxn=stonemax_extendarray();
        printf("%d %d\n",minn,maxn);
    }
}

不取模,空间压缩了,也是O(n^3),空间降了,伟哥的代码

#include <iostream>
#include <vector>
#include <fstream>
using namespace std;

const int MAXINT = 2147483647;

struct MinSum{
public:
    int get_min_score(vector<int> const &stones){
        vector<int> sum(stones.size(), 0);
        vector<vector<int> > dp(stones.size(), sum);
        sum[0] = stones[0];
        for (int i = 1; i < stones.size(); ++ i)sum[i] = sum[i - 1] + stones[i];
        for (int j = 1; j < stones.size(); ++ j){
            for (int i = 0; i < stones.size(); ++ i){
                dp[i][j] = MAXINT;
                for (int k = 0; k <j; ++ k){
                    int cur_temp = dp[i][k] + dp[(i + k + 1) % stones.size()][j - k - 1];
                    dp[i][j] = (dp[i][j] > cur_temp ? cur_temp : dp[i][j]);
                }
                int tail_index = (i + j) % stones.size();
                int cur_sum_temp = 0;
                if (tail_index > i)cur_sum_temp = sum[tail_index] - (i == 0 ? 0 : sum[i - 1]);
                else cur_sum_temp = sum[sum.size() - 1] - (i == 0 ? 0 : sum[i - 1]) + sum[tail_index];
                dp[i][j] += cur_sum_temp;
            }
        }
        int result = dp[0][stones.size() - 1];
        for (int i = 1; i < stones.size(); ++ i)result = (result < dp[i][stones.size() - 1] ? result : dp[i][stones.size() - 1]);
        return result;
    }
};

struct MaxSum{
public:
    int get_max_score(vector<int> const &stones){
        vector<int> sum(stones.size(), 0);
        vector<vector<int> > dp(stones.size(), sum);
        sum[0] = stones[0];
        for (int i = 1; i < stones.size(); ++ i)sum[i] = sum[i - 1] + stones[i];
        for (int j = 1; j < stones.size(); ++ j){
            for (int i = 0; i < stones.size(); ++ i){
                dp[i][j] = 0;
                for (int k = 0; k <j; ++ k){
                    int cur_temp = dp[i][k] + dp[(i + k + 1) % stones.size()][j - k - 1];
                    dp[i][j] = (dp[i][j] < cur_temp ? cur_temp : dp[i][j]);
                }
                int tail_index = (i + j) % stones.size();
                int cur_sum_temp = 0;
                if (tail_index > i)cur_sum_temp = sum[tail_index] - (i == 0 ? 0 : sum[i - 1]);
                else cur_sum_temp = sum[sum.size() - 1] - (i == 0 ? 0 : sum[i - 1]) + sum[tail_index];
                dp[i][j] += cur_sum_temp;
            }
        }
        int result = dp[0][stones.size() - 1];
        for (int i = 1; i < stones.size(); ++ i)result = (result > dp[i][stones.size() - 1] ? result : dp[i][stones.size() - 1]);
        return result;
    }
};

class Solution{
private:
public:
    void solve(){
        //ifstream infile("187in.txt");
        //cin.rdbuf(infile.rdbuf());
        int num_stone;
        while (cin >> num_stone){
            vector<int> stones(num_stone, 0);
            for (int i = 0; i < num_stone; ++ i)cin >> stones[i];
            MinSum min_s;
            MaxSum max_s;

            cout << min_s.get_min_score(stones) << ' ' << max_s.get_max_score(stones) << endl;
        }
    }
};


int main(){
    Solution so;
    so.solve();
    return 0;
}

ahdoc大神说有n^2算法,要给予一个不等式,另外ACRush还有一个nlogn的高端算法,基于斐波那契堆的贪心算法,这个就不去深究了。

Posted by richard爱闹 - 10月 6 2014
如需转载,请注明: 本文来自 Richard