ACM寒假集训动态规划专题

ACM寒假集训数论专题

动态规划大致包括3步:
1.划分状态,即将原问题划分成几个子问题.
2.状态转移,即原问题如何被子问题推出.
3.边界确认,即初始状态及最小子问题.

部分题解如下:

Super Jumping! Jumping! Jumping!

Nowadays, a kind of chess game called “Super Jumping! Jumping! Jumping!” is very popular in HDU. Maybe you are a good boy, and know little about this game, so I introduce it to you now.

start→1→3→2→end

The game can be played by two or more than two players. It consists of a chessboard(棋盘)and some chessmen(棋子), and all chessmen are marked by a positive integer or “start” or “end”. The player starts from start-point and must jumps into end-point finally. In the course of jumping, the player will visit the chessmen in the path, but everyone must jumps from one chessman to another absolutely bigger (you can assume start-point is a minimum and end-point is a maximum.). And all players cannot go backwards. One jumping can go from a chessman to next, also can go across many chessmen, and even you can straightly get to end-point from start-point. Of course you get zero point in this situation. A player is a winner if and only if he can get a bigger score according to his jumping solution. Note that your score comes from the sum of value on the chessmen in you jumping path.
Your task is to output the maximum value according to the given chessmen list.

Input
Input contains multiple test cases. Each test case is described in a line as follow:
N value_1 value_2 …value_N
It is guarantied that N is not more than 1000 and all value_i are in the range of 32-int.
A test case starting with 0 terminates the input and this test case is not to be processed.

Output
For each case, print the maximum according to rules, and one line one case.

大致题意
给出n个数,求一个单调递增的子序列(该子序列各项的和最大),输出该子序列各项的和.

思路
设之前i-1个数中所取的最后一个数是num1,
对于第i个数num2,如果num2>num1,则有取或不取两种可能.如果取了,之后要取的数必须大于他.
转移方程如下:
dp[i][num1]=max(dp[i+1][num1],num2+dp[i+1][num2]).
当然,其中还需要进行优化,num1和num2都可能是1e9之类的大数字,这里我选择通过排序的后各数字的下标来表示num1和num2.

代码如下:

#include<bits/stdc++.h>

using namespace std;
typedef long long ll;
#define finc(i,a,b) for(int i=(a);i<(b);i++)
#define fdec(i,a,b) for(int i=(b);i-->(a);)

bool cmp(pair<int, int> a, pair<int, int> b)
{
    if (a.first != b.first) return a.first < b.first;
    return a.second > b.second;
}

int main()
{
    ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
    int test = 1; //cin >> test;
    int n;
    cin >> n;
    while (n)
    {
        vector<pair<int, int>> data(n + 1);
        finc(i, 1, n + 1)
            cin >> data[i].first, data[i].second = i;
        sort(data.begin(), data.end(), cmp);
        vector<ll> dp(n + 1);
        finc(i, 1, n + 1)
            if (data[n].second >= i)
                dp[i] = data[n].first;
        fdec(i, 1, n)
            finc(j, 1, n + 1)
            if (data[i].second >= j)
                dp[j] = max(dp[j], data[i].first + dp[data[i].second]);
        cout << dp[1] << endl;
        cin >> n;
    }

    return 0;
}

Flipping Coins

Here’s a jolly and simple game: line up a row ofNidentical coins, all with the heads facingdown onto the table and the tails upwards, and for exactlyKtimes take one of the coins, toss itinto the air, and replace it as it lands either heads-up or heads-down. You may keep all of thecoins that are face-up by the end.

Being, as we established last year, a ruthless capitalist, you have resolved to play optimally towin as many coins as you can. Across all possible combinations of strategies and results, whatis the maximum expected (mean average) amount you can win by playing optimally?

Input
One line containing two space-separated integers:
–N(1≤N≤400), the number of coins at your mercy;
–K(1≤K≤400), the number of flips you must perform.
Output
Output the expected number of heads you could have at the end, as a real number. The outputmust be accurate to an absolute or relative error of at most 10e-6.

大致题意
有a枚反面朝上的硬币,每一次操作你可以选择其中一枚硬币并抛起,在b次操作后,求最终正面朝上的硬币数目最大的期望值.

思路
对于i枚反面朝下的硬币,第j次操作后的期望值的状态转移方程为:
dp[i][j]=0.5dp[i][j-1]+0.5(1+dp[i-1][j-1]).

代码如下:

#include<bits/stdc++.h>

using namespace std;
typedef long long ll;
#define finc(i,a,b) for(int i=(a);i<(b);i++)
#define fdec(i,a,b) for(int i=(b);i-->(a);)

int main()
{
    ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
    int test = 1; //cin >> test;
    while (test--)
    {
        int a, b; cin >> a >> b;
        vector<vector<double>> dp(a + 1, vector<double>(b + 1));
        finc(i, 1, a + 1)
            dp[i][1] = 0.5;
        finc(i, 1, b + 1)
            dp[1][i] = 0.5;
        finc(i, 2, a + 1)
            finc(j, 2, b + 1)
            dp[i][j] = 0.5 * (1 + dp[i - 1][j - 1]) + 0.5 * dp[i][j - 1];
        printf("%.8lf\n", dp[a][b]);
    }

    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值