1 solutions
-
0
分析
看起来就很 DP。设 表示前 种面值的钞票进行了一些交换,此时 Alice 有 元钱,Bob 有 元钱,最少的交换次数。
设刚开始三人分别有 元钱,目标是三人分别有 元钱。
初始状态 。枚举第 种面值的钞票,Alice 和 Bob 各留下几张转移。
这样时间复杂度是 ,过不了。
加两个优化:
- 面值的考虑顺序是不影响结果的,先考虑面值较小的,此时有值的状态不会很多,再考虑面值较大的,这样的钞票数量不会很多,比较优。记忆化搜索。
- 从小到大考虑时,如果剩下的面值的 不整除 或者 那就无解。
这时候跑得就比较快了,能够稳定跑进 200ms。
实现
#include <cstdio> #include <cstring> #include <iostream> using namespace std; const int N = 4, M = 7, K = 2005, val[M] = {0, 1, 5, 10, 20, 50, 100}, d[M] = {1, 5, 10, 10, 50, 100}, INF = 0x3f3f3f3f; int f[M][K][K], x[N], s[N], e[N], num[N][M], tot[M], n; int calc(int i, int j, int k) { return (abs(j - num[1][i]) + abs(k - num[2][i]) + abs(tot[i] - j - k - num[3][i])) >> 1; } int F(int i, int j, int k) { if (i == M - 1) return j == e[1] && k == e[2] ? 0 : INF; if ((e[1] - j) % d[i] || (e[2] - k) % d[i]) return INF; int J = j + n, K = k + n; if (f[i][J][K] != -1) return f[i][J][K]; f[i][J][K] = INF; for (int x = 0; x <= tot[i + 1]; x++) for (int y = 0; x + y <= tot[i + 1]; y++) f[i][J][K] = min(f[i][J][K], F(i + 1, j + (x - num[1][i + 1]) * val[i + 1], k + (y - num[2][i + 1]) * val[i + 1]) + calc(i + 1, x, y)); return f[i][J][K]; } int main() { cin >> x[1] >> x[2] >> x[3]; for (int i = 1; i < N; i++) for (int j = 1; j < M; j++) cin >> num[i][M - j]; for (int i = 1; i < N; i++) for (int j = 1; j < M; j++) tot[j] += num[i][j], s[i] += num[i][j] * val[j]; e[1] = s[1] + x[3] - x[1], e[2] = s[2] + x[1] - x[2], e[3] = s[3] + x[2] - x[3]; if (e[1] < 0 || e[2] < 0 || e[3] < 0) return puts("impossible"), 0; memset(f, -1, sizeof(f)), n = s[1] + s[2] + s[3]; int ans = F(0, s[1], s[2]); if (ans == INF) puts("impossible"); if (ans != INF) cout << ans << endl; return 0; }
- 1
Information
- ID
- 1021
- Time
- 1000ms
- Memory
- 256MiB
- Difficulty
- 10
- Tags
- (None)
- # Submissions
- 8
- Accepted
- 2
- Uploaded By