Dire Wolf HDU

题目链接

一开始很自然的想到了贪心,跑了一下贪心,发现无法处理某一段已经被选走的情况,根据数据范围,区间dp比较适合,能储存区间取样信息

设dp[i][j]为已经杀死区间[i,j]的最小值,可以得到转移方程,dp[i][j] = min(dp[i][k-1]+dp[k+1][j]+a[k]+b[i-1]+b[j+1]),也就是说选用k为中间点,合并i-(k-1),(k+1)-j两个区间,且这两个区间已经被选走,能产生的影响为这两个区间的另一侧,注意初始化将非法区域设为0

#include<bits/stdc++.h>
using namespace std;
#define lowbit(x) ((x)&(-x))
typedef long long LL;
typedef pair<int,int> pii;

int a[203], b[203], dp[203][203];


void run_case() {
    int n; cin >> n;
    memset(dp, 0, sizeof(dp));
    for(int i = 1; i <= n; ++i) cin >> a[i];
    for(int i = 1; i <= n; ++i) cin >> b[i];
    a[0] = a[n+1] = b[0] = b[n+1] = 0;
    for(int i = 1; i <= n; ++i)
        for(int j = i+1; j <= n; ++j)
            dp[i][j] = 0x3f3f3f3f;
    for(int i = 1; i <= n; ++i) dp[i][i] = a[i] + b[i-1] + b[i+1];
    for(int i = n-1; i >= 1; --i) {
        for(int j = i+1; j <= n; ++j) {
            for(int k = i; k <= j; ++k) {
                dp[i][j] = min(dp[i][j], dp[i][k-1]+dp[k+1][j]+a[k]+b[i-1]+b[j+1]);
            }
        }
    }
    cout << dp[1][n] << "
";
}
 
int main() {
    ios::sync_with_stdio(false), cin.tie(0);
    cout.flags(ios::fixed);cout.precision(10);
    int t; cin >> t;
    for(int i = 1; i <= t; ++i) {
        cout << "Case #" << i << ": ";
        run_case();
    }
    //cout.flush();
    return 0;
}
View Code
原文地址:https://www.cnblogs.com/GRedComeT/p/12350039.html