2020暑期训练2

DP

  • A - Frog 1
  • B - Frog 2
  • C - Vacation
  • D - Proud Merchants
  • E - Knapsack 1
  • G - Knapsack 2
  • I - Longest Path

题单链接

A - Frog 1

显然, d p [ i ] = min ⁡ ( d p [ i − 1 ] + ∣ h [ i ] − h [ i − 1 ] ∣ , d p [ i − 2 ] + ∣ h [ i ] − h [ i − 2 ] ∣ ) dp[i]=\min(dp[i-1]+|h[i]-h[i-1]|,dp[i-2]+|h[i]-h[i-2]|) dp[i]=min(dp[i1]+h[i]h[i1],dp[i2]+h[i]h[i2])

	ans[2] = abs(h[2] - h[1]);
	for (int i = 3; i <= n; ++i)
		ans[i] = min(ans[i - 1] + abs(h[i] - h[i - 1]), ans[i - 2] + abs(h[i] - h[i - 2]));

B - Frog 2

和A差不多,只不过最小值不是从前两个里面取而是由k决定

	for (int i = 1; i <= n; ++i)
	    h[i] = read();
	for (int i = 2; i <= n; ++i)
	{
	    ans[i] = INF;
	    for (int j = 1; j <= k; ++j)
	    {
	        if (i > j)
	            ans[i] = min(ans[i - j] + abs(h[i] - h[i - j]), ans[i]);
	    }
	}
	printf("%d", ans[n]);

C - Vacation

状态转移方程也比较容易得出:
d p A [ i ] = a [ i ] + max ⁡ ( d p B [ i − 1 ] , d p C [ i − 1 ] ) dp_A[i]=a[i]+\max(dp_B[i-1],dp_C[i-1]) dpA[i]=a[i]+max(dpB[i1],dpC[i1])
d p B [ i ] = b [ i ] + max ⁡ ( d p A [ i − 1 ] , d p C [ i − 1 ] ) dp_B[i]=b[i]+\max(dp_A[i-1],dp_C[i-1]) dpB[i]=b[i]+max(dpA[i1],dpC[i1])
d p C [ i ] = c [ i ] + max ⁡ ( d p A [ i − 1 ] , d p B [ i − 1 ] ) dp_C[i]=c[i]+\max(dp_A[i-1],dp_B[i-1]) dpC[i]=c[i]+max(dpA[i1],dpB[i1])
那么可以得到这样的代码:

	for (int i = 1; i <= n; ++i)
    {
        a[i] = read(), b[i] = read(), c[i] = read();
        dp[i][0] = a[i] + max(dp[i-1][2], dp[i-1][1]);
        dp[i][1] = b[i] + max(dp[i-1][0], dp[i-1][2]);
        dp[i][2] = c[i] + max(dp[i-1][1], dp[i-1][0]);
    }
    printf("%d\n",max(max(dp[n][0], dp[n][1]), dp[n][2]));

D - Proud Merchants

01背包的进化版。
直接做肯定不行,需要按照某种顺序进行排序。
假设在钱足够的情况下有A、B两种东西要买,那么先买A至少需要 p A + q B p_A+q_B pA+qB 的钱,先买B至少需要 p B + q A p_B+q_A pB+qA 的钱,因此如果 q A − p A > q B − p B q_A-p_A>q_B-p_B qApA>qBpB,先买A。但是还需要考虑到, d p [ j ] = max ⁡ ( d p [ j − p [ i ] ] + v [ i ] , d p [ j ] ) dp[j]=\max(dp[j-p[i]]+v[i],dp[j]) dp[j]=max(dp[jp[i]]+v[i],dp[j]) 的时候,这个j是最先买的,也就是说在dp的时候选取的商品和其在数组中的顺序是正好相反的,因此排序的时候需要反过来排。

struct merchant
{
    int p, q, v;
    const bool operator<(const merchant &b) const
    {
        return q - p < b.q - b.p;
    }
} s[509];
int dp[5009];
int main()
{
    //freopen("in.txt","r",stdin);
    //freopen("data.txt","w",stdout);
    //std::ios::sync_with_stdio(false);
    //std::cin.tie(0);
    int n, m;
    while (~scanf("%d%d", &n, &m))
    {
        memset(dp, 0, sizeof(int)*5009);
        for (int i = 1; i <= n; ++i)
            scanf("%d%d%d", &s[i].p, &s[i].q, &s[i].v);
        sort(s + 1, s + n + 1);
        for (int i = 1; i <= n; ++i)
            for (int j = m; j >= s[i].q; --j)
                dp[j] = max(dp[j], dp[j - s[i].p] + s[i].v);
        printf("%d\n", dp[m]);
    }
    //fclose(stdin);
    //fclose(stdout);
    return 0;
}

E - Knapsack 1

01背包模板题

    for (int i = 1; i<= n; ++i)
        for (int j = w; j >= p[i]; --j)
            dp[j] = max(dp[j], dp[j - p[i]] + v[i]);

G - Knapsack 2

巨型背包
这数据范围直接枚举容量一定会T,而N和v都很小,因此求装到某个价值所需要的最小容量,最后降序枚举价值,第一个能装下的就是答案

    for (int i = 1; i <= n; ++i)
        p[i] = read(), v[i] = read();
    for (ull i = 1; i < maxn; ++i)
        dp[i] = INF;
    for (int i = 1; i <= n; ++i)
        for (int j = maxn - 1; j >= v[i]; --j)
            dp[j] = min(dp[j], dp[j - v[i]] + p[i]);
    for (int i = maxn - 1; i >= 0; --i)
        if (dp[i] <= w)
        {
            cout << i << '\n';
            break;
        }

I - Longest Path

这个不知道怎么DP,看起来倒像是拓扑排序,不过还是记忆化搜索写起来比较方便。

vector<int> edge[maxn];
int dis[maxn], ans;
bool vis[maxn];
void dfs(int x)
{
    if (vis[x])
        return;
    vis[x] = true;
    for (int i = 0; i < edge[x].size(); ++i)
    {
        dfs(edge[x][i]);
        dis[x] = max(dis[x], dis[edge[x][i]] + 1);
    }
    ans = max(ans, dis[x]);
}
int main()
{
    //freopen("in.txt","r",stdin);
    //freopen("data.txt","w",stdout);
    //std::ios::sync_with_stdio(false);
    //std::cin.tie(0);
    int n = read(), m = read();
    while (m--)
    {
        int x = read(), y = read();
        edge[x].emplace_back(y);
    }
    for (int i = 1; i <= n; ++i)
        dfs(i);
    cout << ans << '\n';
    //fclose(stdin);
    //fclose(stdout);
    return 0;
}

你可能感兴趣的:(#,其他)