题意:
给你三个杯子,a,b,c,没有刻度,刚开始c杯是满的,倒水的要求,要么倒出水的杯子倒空,要么倒入杯子倒满.
结果:
要求某个杯子内有d水量,并且倒出的水量最少,如果倒不出d水量,那么倒出d1(d1<d)水量,并且倒出的水量最少
解题思路:
总的水量为c,只要知道前俩个杯子的水量,那么第三个杯子的水量就确定了,所以,状态数最大只有a * b种,所以一个二维数组标记状态就够.
要求倒出的水量最少,那么使用优先队列,按照倒出的水量最少开始搜索.
初始化结点为(0,0,c),由这个结点开始往外扩展,此时倒出的水量为0,结果d为0,注意代码内有个特判,如果d >= c,那么最大的d就是c,倒出的水量为0
#include <iostream> #include <stdio.h> #include <memory.h> #include <queue> using namespace std; const int NN = 201; int a[3]; int d; int maxD = -1; int maxNum = 0; //记录c1,c2,已知c1,c2,c3就可以确定 int vis[NN][NN]; class State { public: int a[3]; int waterNum; State() : waterNum(0) { a[0] = 0; a[1] = 0; a[2] = 0; } State(int d1, int d2, int d3, int w) : waterNum(w) { a[0] = d1; a[1] = d2; a[2] = d3; } bool operator ()(State& a, State& b) { return a.waterNum > b.waterNum; } }; priority_queue<State, vector<State>, State> q; void bfs() { while (!q.empty()) { State s = q.top(); q.pop(); for(int i = 0; i < 3; i++) for(int j = 0; j < 3; j++) { if(i == j || s.a[i] == 0) continue; //把水从i导入j中 //要么i倒空,要么j倒满 int dj = a[j] - s.a[j]; if(dj == 0) //j是满的,不能倒 continue; //i杯内的水量 int di = s.a[i]; //倒出的水量 State ss(s.a[0], s.a[1], s.a[2], s.waterNum); if(dj > di) { //i杯倒空 ss.waterNum = ss.waterNum + di; ss.a[i] = 0; ss.a[j] = ss.a[j] + di; } else { //j杯倒满 ss.waterNum = ss.waterNum + dj; ss.a[i] = di - dj; ss.a[j] = ss.a[j] + dj; } if(vis[ss.a[0]][ss.a[1]]) continue; //判断当前状态 if(ss.a[i] <= d && ss.a[i] > maxD) { maxD = ss.a[i]; maxNum = ss.waterNum; } if(ss.a[j] <= d && ss.a[j] > maxD) { maxD = ss.a[j]; maxNum = ss.waterNum; } if(maxD == d) return; q.push(ss); vis[ss.a[0]][ss.a[1]] = 1; } } } void clear() { while (!q.empty()) q.pop(); memset(vis, 0, sizeof(vis)); maxNum = 0; maxD = 0; } int main() { int num; cin >> num; while (num--) { clear(); cin >> a[0] >> a[1] >> a[2] >> d; if(d >= a[2]) { cout << 0 << " " << a[2] << endl; continue; } State state(0, 0, a[2], 0); q.push(state); vis[0][0] = 1; bfs(); if(maxD == 0) cout << 0 << " " << 0 << endl; else cout << maxNum << " " << maxD << endl; } return 0; }