合人问题

【题目描述】
众所周知,小葱同学擅长合并,尤其把两个人合并成一个人。但小葱只擅长合并两
个人的情况,当有很多个人之后就会比较苦恼。现在小葱给了你 n 个人排成一个环(即
第一个人和最后一个人相邻),并且每个人左手和右手上各有一个数。每次你可以合并
相邻的两个人,合并这两个人的代价为他们右手的数的差的绝对值,合并之后会变成一
个新的人,新的人左手的数是原来左边的人左手的数,右手的数是原来右边的人右手的
数。现在小葱希望你通过 n − 1 次合并把所有人合并成一个人,并且使得代价最小。求
最小代价。
【输入格式】
从文件 merge.in 中读入数据。
第一行包括 1 个正整数 n。
接下来 n 行每行 2 个正整数代表每个人左手和右手的数。
【输出格式】
输出到文件 merge.out 中。
输出一行一个整数代表最小代价。
【样例 1 输入】
3
1 1
2 2
3 3
【样例 1 输出】
2
【样例 1 解释】
先合并前两个人。


没有心态,模考3道题只有100pts

就是这道区间DP

把环转成链

然后dp[i][j]表示从i到j的最小代价

下面给出代码:

#include<iostream>
#include<algorithm>
#include<cstring>
#include<string>
#include<cmath>
#include<cstdio>
#include<cstdlib>
using namespace std;
inline int rd(){
    int x=0,f=1;
    char ch=getchar();
    for(;!isdigit(ch);ch=getchar()) if(ch=='-') f=-1;
    for(;isdigit(ch);ch=getchar()) x=x*10+ch-'0';
    return x*f;
}
inline void write(int x){
    if(x<0) putchar('-'),x=-x;
    if(x>9) write(x/10);
    putchar(x%10+'0');
    return ;
}
int head[100006],tail[100006];
int dp[500][500];
int main(){int n;
    n=rd();
    memset(dp,127,sizeof(dp));
    for(int i=1;i<=n;i++){
        head[i]=rd();
        tail[i]=rd();
        head[i+n]=head[i];
        tail[i+n]=tail[i];
        dp[i][i]=0;
        dp[i+n][i+n]=0;
    }
    for(int l=1;l<n;l++){
        for(int i=1;i<=2*n-l;i++){
            int j=i+l;
            for(int k=i;k<j;k++) dp[i][j]=min(dp[i][j],dp[i][k]+dp[k+1][j]+abs(tail[k]-tail[j]));
        }
    }
    int minn=1e9;
    for(int i=1;i<=n;i++) minn=min(minn,dp[i][i+n-1]);
    printf("%d",minn);
    return 0;
}
蒟蒻总是更懂你✿✿ヽ(°▽°)ノ✿
原文地址:https://www.cnblogs.com/WWHHTT/p/9821428.html