题意:
给定3个杯子的容量, 然后一开始第3个杯子水是满的, 求出最少倒多少升水才能让某个杯子有d 升水, 如果无法做到, 求出d',(d' < d 且尽量接近d)
#include <iostream> #include <queue> #include <cstdio> #include <cstring> using namespace std; const int maxn = 200 + 7; struct node { int v[3], dist; bool operator < (const node& a) const { return dist > a.dist; } }; int D[maxn]; void update(node u) { for(int i = 0; i < 3; i++) { if(D[u.v[i]] == -1 || u.dist < D[u.v[i]]) //如果这个水量的距离没被标记过, 或者当前该水量的距离比记录距离小, 更新记录距离 D[u.v[i]] = u.dist; } } void solve(int a, int b, int c, int d) { int cap[3]; memset(D, -1 , sizeof(D)); cap[0] = a, cap[1] = b, cap[2] = c; bool vis[maxn][maxn]; memset(vis,0,sizeof(vis)); priority_queue<node> q; node st; st.v[0] = st.v[1] = 0, st.v[2] = c,st.dist = 0; vis[0][0] = 1; q.push(st); while(!q.empty()) { node u = q.top(); update(u); if(D[d] > 0){// printf("%d %d ", D[d], d); return; } for(int i = 0; i < 3; i++) for(int j = 0; j < 3; j++) { if(i != j) // i pull j { if(u.v[i] == 0 || u.v[j] == cap[j]) continue; int amount = min(u.v[i] , cap[j] - u.v[j]); //j full or i empty node u2; memcpy(&u2, &u, sizeof(u)); u2.v[i] -= amount , u2.v[j] += amount; u2.dist += amount; if(!vis[u2.v[0]][u2.v[1]]){ vis[u2.v[0]][u2.v[1]] = 1; q.push(u2); } } } q.pop(); } for(;d>=0;){//找不到d, 往下找d' (题目规定d' < d) while( D[d] == -1) d--; printf("%d %d ", D[d], d); return; } } int main() { int T, a, b, c, d; scanf("%d", &T); while(T--) { scanf("%d%d%d%d", &a, &b, &c, &d); solve(a,b,c,d); } return 0; }