2019河北省大学生程序设计竞赛:C.分治

91 阅读2分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第20天,点击查看活动详情

2019河北省大学生程序设计竞赛——C-分治

C-分治

你是DEEP国的大军师,辅佐一个非常有野心的国王,这位国王非常有野心,他计划攻占 n 个国家。在地图上,这些国家排成一行。 探子已经查明,当攻打一个国家 i 时,为了防止国家间的联合对抗,需要给该国家周围,所有未被攻占的国家支付costicost_icosti​ 个金币,即对于国家 i,它左侧第一个已被攻打的国家为 l,右侧第一个已被攻打的国家为 r,则他需要给[l+1,i-1] 和 [i+1,r-1] 之间的国家支付金币。如果 l 不存在,则需要给 [1, i-1] 之间的所有国家支付金币;若 r 不存在,则需要给 [i+1,n] 之间的所有国家支付金币。

现在,你的下属已经给你提供了每个国家需要支付金币的数量。为了满足国王的野心,你需要计算出攻占完所有国家需要的最小花费。

输入描述:

第一行是一个整数 T,代表接下来有T组数据。
接下来每组数据
第一行有一个整数 n,代表要攻占的国家数目。
第二行共 n 个整数,代表攻占每个国家前,需要支付给其周围未被攻占国家 costi个金币。
1T501≤n≤,1≤costi≤10000

输出描述:

对于每组数据输出一行,代表需要支付的最小花费。                        

输入

2
1
1
3
1 1 2

输出

0
2

问题解析

区间DP。

二维状态数组f,f[i] [j]表示攻打第i~第j个国家,所需的最小花费为f[i] [j],f[i] [i]=0。

那么攻打i~j之间的国家k时,就有:*f[i] [j]=min(f[i] [j],f[i] [k-1]+f[k+1] [j]+(j-i)a[k]) ,其中a[k]是攻打第k个国家时需要给其它国家的金币,要给金币的国家数为i到j中除了k以外的全部国家,所以为:j-i。

考虑边界问题:

当我们要攻打第i个国家时:*f[i] [j]=min(f[i] [j],f[i+1] [j]+(j-i)a[i]) ;

攻打第j个国家时:*f[i] [j]=min(f[i] [j],f[i] [j-1]+(j-i)a[j]) ;

AC代码

#include<iostream>
using namespace std;
#include<vector>
#include<algorithm>
#include<math.h>
#include<set>
#include <random>
#include<numeric>
#include<string>
#include<string.h>
#include<iterator>
#include<fstream>
#include<map>
#include<unordered_map>
#include<stack>
#include<list>
#include<queue>
#include<iomanip>
#include<bitset>#pragma GCC optimize(2)
#pragma GCC optimize(3)#define endl '\n'
#define int ll
#define PI acos(-1)
#define INF 0x3f3f3f3f
typedef long long ll;
typedef unsigned long long ull;
typedef pair<ll, ll>PII;
const int N = 105;
​
int f[N][N], a[N], n;
void solve()
{
    cin >> n;
    for (int i = 0; i <= n; i++)
        for (int j = 0; j <= n; j++)
        {
            f[i][j] = 1e9;
            if (i == j)f[i][j] = 0;
        }
    for (int i = 1; i <= n; i++)cin >> a[i];
    for (int len = 2; len <= n; len++)
    {
        for (int i = 1; i <= n - len + 1; i++)
        {
            int j = i + len - 1;
            for (int k = i + 1; k < j; k++)
            {
                f[i][j] = min(f[i][j], f[i][k - 1] + f[k + 1][j] + (j - i) * a[k]);
            }
            f[i][j] = min(f[i][j], f[i][j - 1] + (j-i) * a[j]);
            f[i][j] = min(f[i][j], f[i + 1][j] + (j-i) * a[i]);
        }
    }
    cout << f[1][n] << endl;
}
​
signed main()
{
​
    ios_base::sync_with_stdio(false);
    cin.tie(nullptr);
    cout.tie(nullptr);
    int t = 1;
    cin >> t;
​
    while (t--)
    {
        solve();
    }
    return 0;
}