• 题解 【P4026 [SHOI2008]循环的债务】


    (Large exttt{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;
    }
    
  • 相关阅读:
    线程之间通信 等待(wait)和通知(notify)
    python输出所有三位数的回文数
    python之1100之间的总和,奇数和,偶数和
    python之九九乘法表
    数据类型
    python之判断闰年
    python的下载与安装
    pycharm的下载与安装
    Windows Phone 7 学习流程攻略(二)
    Windows Phone 7 学习流程攻略(三)
  • 原文地址:https://www.cnblogs.com/RedreamMer/p/15518571.html
Copyright © 2020-2023  润新知