CF GYM 100703F Game of words

题意:两个人玩n个游戏,给出每人玩每个游戏的时间,两个人需要在n个游戏中挑m个轮流玩,求最短时间。

解法:dp。(这场dp真多啊……话说也可以用最小费用最大流做……然而并不会XD)dp[i][j][k]表示玩前i个游戏时第一个人玩了j个游戏,第二个人玩了k个游戏,所以状态转移方程为dp[i][j][k] = min(dp[i][j][k], dp[i - 1][j - 1][k] + a[i], dp[i - 1][j][k - 1] + b[i]),第一个维度在空间上可以优化掉,再处理一下边界,但是如果写成dp[i][j + 1][k] = dp[i - 1][j][k] + a[i], dp[i][j][k + 1] = dp[i - 1][j][k] + b[i]看起来更优美……不需要处理边界……但是跟我的思考方式有些不同……

代码:

#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<string>
#include<string.h>
#include<math.h>
#include<limits.h>
#include<time.h>
#include<stdlib.h>
#include<map>
#include<queue>
#include<set>
#include<stack>
#include<vector>
#define LL long long
using namespace std;
int a[405], b[405];
int dp[405][405];
int main()
{
    int n, m;
    while(~scanf("%d%d", &m, &n))
    {
        for(int i = 0; i < n; i++)
            scanf("%d", &a[i]);
        for(int i = 0; i < n; i++)
            scanf("%d", &b[i]);
        memset(dp, 0x3f3f3f3f, sizeof dp);
        dp[0][0] = 0;
        for(int i = 0; i < n; i++)
        {
            for(int j = i + 1; j >= 0; j--)
            {
                for(int k = i - j + 1; k >= 0; k--)
                {
                    if(j == 0 && k == 0)
                        continue;
                    if(j == 0)
                        dp[j][k] = min(dp[j][k], dp[j][k - 1] + b[i]);
                    else if(k == 0)
                        dp[j][k] = min(dp[j][k], dp[j - 1][k] + a[i]);
                    else
                        dp[j][k] = min(dp[j][k], min(dp[j - 1][k] + a[i], dp[j][k - 1] + b[i]));
                }
            }
        }
        printf("%d
", min(dp[m / 2][m - m / 2], dp[(m + 1) / 2][m - (m + 1) / 2]));
    }
    return 0;
}

  

原文地址:https://www.cnblogs.com/Apro/p/4685790.html