Fill
题目大意:
给定三个水杯,a,b,c ,并且 a,b 为空杯,c 倒满,
给定一个容量 d 要求给出当,杯中有出现容量为d 的情况时,给出最少的水交换容量,
如果没有 则给出d' 要求 d' 尽可能得接近 d
思路:
使用爆搜,广度优先遍历,对应的记录每一个状态下的 每一个杯子的含有的水量和已经交换的水的容量
当出现d容量的情况时退出,否则从 d 开始往下遍历最接近d 容量的 d' 的交换容量值。
同时需要注意,由于是最少的容量交换值,所以要用优先队列先拿出容量最小的节点求解。
代码:
#include<iostream>
#include<queue>
#include<cstring>
using namespace std;
const int MAXN = 205;
struct node{
//三杯水的容量
int v[3];
//在这个状态下的 倒水量
int dist;
bool operator <(const node &b) const{
// 优先队列的 operator 和 普通的sort 是相反的,
//即 从小到大,用 > 反之用 >
return dist>b.dist;
}
} nnode;
// 出现杯子为 i升水的时候需要倒水的量
int ans[MAXN],cap[3];
bool vis[MAXN][MAXN];
//更新最小倒水量
void update_ans(const node &a){
for(int i=0;i<3;i++){
//ans 表示对应水量的 倒水量
int d = a.v[i];
if(ans[d]<0 || a.dist < ans[d]) ans[d] = a.dist;
}
}
void bfs( int d){
nnode.v[0] = 0; nnode.v[1] = 0; nnode.v[2] = cap[2];
nnode.dist = 0;
priority_queue<node> que;
que.push(nnode);
vis[0][0] = 1;
while(!que.empty()){
node now = que.top(); que.pop();
update_ans(now);
if(ans[d] >= 0) break;
for(int i=0;i<3;i++)
for(int j=0;j<3;j++)
if(i!=j){
if(now.v[i]<=0 || now.v[j] >=cap[j]) continue;
//保证每次都是在都是独立改变
node temp = now;
//计算能倒的水
int water = min(temp.v[i],cap[j] - temp.v[j]);
temp.v[i] -= water;
temp.v[j] += water;
temp.dist += water;
if(vis[temp.v[0]][temp.v[1]]) continue;
vis[temp.v[0]][temp.v[1]] = 1;
que.push(temp);
}
}
}
int main(){
int T,a,b,c,d;
scanf("%d",&T);
while(T--){
scanf("%d%d%d%d",&cap[0],&cap[1],&cap[2],&d);
memset(ans,-1,sizeof(ans));
memset(vis,0,sizeof(vis));
bfs(d);
while(d>=0){
if(ans[d]>=0) {
printf("%d %d\n",ans[d],d);
break;
}
d--;
}
}
return 0;
}