题意:两个人玩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; }