浙江中医药大学暑期训练测试赛十

Problem A: 英雄无敌3(1)

Time Limit: 1 Sec   Memory Limit: 128 MB
Submit: 84   Solved: 14
[ Submit][ Status][ Web Board]

Description

大家知道在英雄无敌3中,每个城堡都需要钱来维持建设,现在有一座很奇怪的金矿,它在第i天只产生si 元的钱,而且如果你在第i天拿到si 元的钱,那么你将在 xi 内(包括第i天)拿不到钱,而在yi天内(包括第i天)一定要再次拿钱。现在有一个着急的玩家,他现在已经拿了第一天的钱,他想知道他最多能拿到多少钱(包含第一天的钱)。

Input

第一行输入一个数t,代表测试案例数

每个案例先输入一个数n(n < =50000),代表总共有几天,接下来有n行,输入3个整数整数分别为si,xi,yi (0<=si<10000,0<=xi < yi)

Output

对于每组案例,输出一个正整数,代表他能拿到的最多钱数

Sample Input

431 1 22 2 33 3 431 1 32 2 43 3 5410 3 107 1 75 2 51 1 251 1 910 3 107 1 75 2 51 1 2

Sample Output

341113

HINT

先贴一下超时的代码:
说明下,这里的dp(i),表示前i天拿到的最大钱数。
超时的话是因为生成树的分支太多了,显然,从小往大的dp是很难得到优化,总之我是没有想到,因为从小
往大dp就相当于一个dfs的过程,实际上并非动态规划,即是,对于每一条可走的路径都走一遍,当然,前提是到达当前
节点时,其钱数比原先要多,但是,这样仍然耗时很多,因为并不能每次都能保留到最优解,而是需要不断对节点上的值
进行更新,于是想到逆序dp。怎样进行逆序dp呢,先说明一下,逆序dp,dp(i)所表示的含义,即第i天以后拿到的最大钱数。
这个时候我们利用先前超时的代码中,相当于一个dfs的过程,是可以每次都能保留到最优解的,为什么呢,我们假设第i天
是可以到达的,那么显然,dp(i)的大小只由后天它能到达的各天的钱数决定,于是,如果访问到了第i天,求出来一个dp(i),
即已经是最优解了,因为dp(i)只会包含它以后可到达天数的钱数,而不会受前面的影响。
以后到达第i天,都可以直接用到这个已经求出的最优解了,于是我们可以做出很大的优化,把一个最坏为O(n!)(这个
我也不太清楚,感觉应该是n!),优化到了O(n^2)
实际上是生成树的分支减少了很大一部分。
#include
#include
#include
using namespace std;
struct day {
int s;
int x;
int y;
}a[50005];
int dp[50005], Max = 0, n;
void make_dp(int l, int r, int v) {
for (int k = l; k <= r && k <= n; ++k) {
if (dp[k] < v + a[k].s) {
dp[k] = v + a[k].s;
make_dp(k + a[k].x, a[k].y + k - 1, dp[k]);
Max = max(dp[k], Max);
}
}
}
int main() {
int t;
scanf("%d", &t);
while (t--) {
scanf("%d", &n);
for (int i = 1; i <= n; ++i) {
scanf("%d%d%d", &a[i].s, &a[i].x, &a[i].y);
if (a[i].x == 0)
a[i].x++;
dp[i] = 0;
}
dp[1] = a[1].s;
make_dp(a[1].x + 1, a[1].y, dp[1]);
printf("%d\n", Max);
}
return 0;
}
#include 
#include 
#include 
using namespace std;
struct day {
    int s;
    int x;
    int y;
}a[50005];
int dp[50005], n;
int make_dp(int l,int r) {
    int Max = 0;
    for(int k = l; k <= n && k <= r; ++k) {
        if(dp[k] == 0) {
            if(a[k].x + k <= n)
                dp[k] = max(dp[k], a[k].s + make_dp(a[k].x + k, a[k].y + k - 1));
            else
                dp[k] = a[k].s;
        }
        Max = max(dp[k], Max);
    }
    return Max;
}
int main() {
    int t;
    scanf("%d", &t);
    while(t--) {
        scanf("%d", &n);
        for(int i = 1; i <= n; ++i) {
            scanf("%d%d%d", &a[i].s, &a[i].x, &a[i].y);
            if(a[i].x == 0)
                a[i].x++;
            dp[i] = 0;
        }
        printf("%d\n", make_dp(1,1));
    }
    return 0;
}



你可能感兴趣的:(算法)