石子合并——圆形版

石子合并的圆形版和直线版差不多,关键是怎么把圆变成直线来处理。
以最小值为例:
1.先初始化mi[m][m];
2.枚举区间长度len,当区间长度为1时,相应的mi[len][i] = 0;
3.枚举起始位置i;
4.枚举插入位置,mi[j][i]代表从i开始,长度为j的最小得分。
5.将圆变成直线的方法是,当i+j大于n时,第二段开始的位置就要重新计算,
设pos为第二段开始的坐标,pos =int pos = (i+j)%n if(pos == 0) pos = n;
dp[i][j] = min(dp[i][j],dp[j][i]+dp[len-j][pos]+getsum[j][i]);
6.getsum(j,i)计算的是从i开始,长度为j的所有石子数量的和,如果i+len-1<=n
getsum(j,i) = sum[j]-sum[i-1];
如果大于
就要算出从第i堆到第n堆的石子数量,和第一队到第pos堆的石子数量

这里写图片描述


#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
using namespace std;
const int inf = 100000000;
const int m = 105;
int mi[m][m];
int ma[m][m];
int a[m];
int sum[m];
int mis,mas,n;

int getsum(int len,int i)
{
    if((i+len-1)<=n) return sum[i+len-1]-sum[i-1];
    else 
    {
        return (sum[n]-sum[i-1]+sum[(i+len-1)%n]);
    }
}

void solve_mi()
{
    for(int i = 0 ; i <= n ; i++)
        for(int j = 0 ; j <= n ; j++)
        {
            mi[i][j] = inf;//初始化最小最大值 
        }

    for(int len = 1 ; len <= n ;len++)//代表区间长度,一定从小区间到大区间 
    {
        for(int i = 1 ; i <= n ; i++)//起始点位置,mi[i][len]代表从i开始长度为n的区间 
        {
            if(len == 1)//长度为1初始值为0 
            {
                mi[len][i] = 0;
                continue;
            }
            for(int j = 1 ; j < len ; j++)//j代表插入位置,mi[j][i]代表从i开始长度为j的区间,原来长度为len,通过j分割为长度为j和len-j两个区间 
            {
                int pos = (i+j)%n;
                if(pos == 0) pos = n;
                int k = getsum(len,i);
                mi[len][i] = min(mi[len][i],mi[j][i]+mi[len-j][pos]+k);
            }
        }
    }
    mis = inf;
    for(int i = 1 ; i <= n ; i++)
    mis = min(mis,mi[n][i]);
}

void solve_ma()
{
    for(int i = 0 ; i <= n ; i++)
        for(int j = 0 ; j <= n ; j++)
        {
            ma[i][j] = 0;
        }

    for(int len = 1 ; len <= n ;len++)
    {
        for(int i = 1 ; i <= n ; i++)
        {
            if(len == 1) 
            {
                ma[len][i] = 0;
                continue;
            }
            for(int j = 1 ; j < len ; j++)
            {
                int pos = (i+j)%n;
                if(pos == 0) pos = n;
                int k = getsum(len,i);
                ma[len][i] = max(ma[len][i],ma[j][i]+ma[len-j][pos]+k);
            }
        }
    }
    mas = 0;
    for(int i = 1 ; i <= n ; i++)
    mas = max(mas,ma[n][i]);
}

int main()
{
    while(~scanf("%d",&n))
    {
        memset(sum,0,sizeof(sum));
        for(int i = 1 ; i <= n ; i++)
        {
            scanf("%d",&a[i]);
            sum[i]= sum[i-1]+a[i];
        }
        solve_mi();
        solve_ma();
        cout<<mis<<" "<<mas<<endl;
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_40240576/article/details/81545597
今日推荐