题解 【P4026 [SHOI2008]循环的债务】
作者:互联网
\(\Large\texttt{P4026 [SHOI2008]循环的债务}\)
萌新不会 DP 捏,只会暴力 DFS。
可能是数据水了,目前最优解第一 130ms,没有卡常。
思路
发现题目约束三人总面值之和不会超过 1000 元,并且对每人小于 10 元的货币个数进行了约束,所以毛咕咕 1 元的货币的个数比较多。
因为我们大力 DFS,枚举每个人最终最优情况中每种面值大于 1 元的货币的个数,最后判断可行性并用 1 元的货币调平。
对于每种货币之间的交换,因为互相独立,对于原来一种货币三人分别有 \(a0,b0,c0\) 个,最终每人分别有 \(a1,b1,c1\) 个,最优交换次数一定是 \(\frac{|a0 - a1| + |b0 - b1| + |c0 - c1|} {2}\),贪心容易证明。
然后就做完了,记得 DFS 加点可行性和最优性剪枝。
代码
int a, b, c, s[3], p[3][6], q[3][6], mx[6], t[3], o[6] = {100, 50, 20, 10, 5, 1}, ans = inf;
int calc() {
int tmp = 0;
rep(i, 0, 2) {
t[i] = s[i];
rep(j, 0, 4) t[i] += o[j] * (p[i][j] - q[i][j]);
if(t[i] < 0 && abs(t[i]) > p[i][5]) return inf;
tmp += abs(t[i]);
}
return tmp / 2;
}
int upd(int n) {
return (abs(p[0][n] - q[0][n]) + abs(p[1][n] - q[1][n]) + abs(p[2][n] - q[2][n])) / 2;
}
void dfs(int n, int now) {
if(now >= ans) return;
if(n == 5) {
ans = min(ans, now + calc());
return;
}
rep(i, 0, mx[n]) rep(j, 0, mx[n] - i) {
q[0][n] = i, q[1][n] = j, q[2][n] = mx[n] - i - j;
dfs(n + 1, now + upd(n));
}
}
signed main() {
// freopen("in1.in", "r", stdin);
a = read();
b = read();
c = read();
s[0] = -a + c;
s[1] = -b + a;
s[2] = -c + b;
rep(i, 0, 2) rep(j, 0, 5) p[i][j] = read(), mx[j] += p[i][j];
dfs(0, 0);
if(ans == inf) cout << "impossible";
else cout << ans;
return 0;
}
标签:P4026,return,int,题解,rep,ans,abs,SHOI2008,mx 来源: https://www.cnblogs.com/RedreamMer/p/15518571.html