Problem E: 【宽搜入门】巧妙取量
Description
【题目描述】
有三个容器,容量分别为 a,b,c(a> b > c ),一开始a装满油,现在问是否只靠abc三个容器量出k升油。如果能就输出“yes”,并且说明最少倒几次,否则输出“no”。例如:10升油在10升的容器中,另有两个7升和3升的空容器,要求用这三个容器倒油,使得最后在abc三个容器中有一个刚好存有5升油,问最少的倒油次数是多少?(每次倒油,A容器倒到B容器,或者A内的油倒完,或者B容器倒满。
10 7 3
(10 0 0)
(3 7 0):第一次
(3 4 3):第二次
(6 4 0):第三次
(6 1 3):第四次
(9 1 0):第五次
(9 0 1):第六次
(2 7 1):第七次
(2 5 3):第八次,出现5了。
Input
【输入格式】
有多组测试数据。
输入a,b,c, k四个正整数( 100 ≥ a > b > c≥1 , 1≤k< 100 )
Output
【输出格式】
如果能得到k就输出两行。
第一行“yes”,第二行为最少的次数
否则输出“no”
Sample Input
10 7 3 5
Sample Output
yes 8
题目链接:
简化代码(如果不能理解,请看后面的详细代码):
#include <bits/stdc++.h> using namespace std; //最关键的两点:一、记录出现的状态,重复状态不入队;二、倒水的次序没有规定 struct Node{ int step, xy[3]; //pre 表示前一步 }; int k, xy[3], X[]={0, 0, 1, 1, 2, 2}, Y[]={1, 2, 0, 2, 0, 1}; map<int, bool> mp; void move(int from, int to, Node now, queue<Node> &q){ int pour=min(now.xy[from], xy[to]-now.xy[to]); if(pour <= 0) return ; now.xy[from] -= pour; now.xy[to] += pour; now.step += 1; int key = now.xy[0]*10000 + now.xy[1]*100 + now.xy[2]; if(mp[key] == false){ q.push(now); mp[key] = true; } } int BFS(){ int i; Node now; now.xy[0]=xy[0], now.xy[1]=0, now.xy[2]=0, now.step=0; queue<Node> q; q.push(now); mp[now.xy[0]*10000] = true; while(!q.empty()){ now = q.front(); q.pop(); if(now.xy[0]==k || now.xy[1]==k || now.xy[2]==k) return now.step; for(i=0; i<6; i++) move(X[i], Y[i], now, q); } return -1; //没有找到 } int main(){ while(cin>>xy[0]>>xy[1]>>xy[2]>>k){ mp.clear(); int ans = BFS(); if(ans != -1) printf("yes\n%d\n", ans); else printf("no\n"); } return 0; }
总结:将倒取的过程抽象了,省去了一些赘余的代码。
详细版代码:
#include <bits/stdc++.h> using namespace std; //最关键的两点:一、记录出现的状态,重复状态不入队;二、倒水的次序没有规定 struct Node{ int a, b, c, step; }now, nex; int a, b, c, k; map<int, bool> mp; int BFS(){ int i, t, pour; now.a=a, now.b=0, now.c=0, now.step=0; queue<Node> q; q.push(now); mp[now.a*10000] = true; while(!q.empty()){ now = q.front(); q.pop(); if(now.a==k || now.b==k || now.c==k) return now.step; nex.step = now.step + 1; //首先步数加 1 //a往b倒 pour = min(now.a, b-now.b); //别写成 min(now.a, b-nex.b)了! if(pour > 0){ nex.a = now.a - pour; nex.b = now.b + pour; nex.c = now.c; t = nex.a*10000+nex.b*100+nex.c; if(mp[t]==false){ q.push(nex); mp[t] = true; } } //a往c倒 pour = min(now.a, c-now.c); if(pour > 0){ nex.a = now.a - pour; nex.b = now.b; nex.c = now.c + pour; t = nex.a*10000+nex.b*100+nex.c; if(mp[t]==false){ q.push(nex); mp[t] = true; } } //b往a倒 pour = min(now.b, a-now.a); if(pour > 0){ nex.a = now.a + pour; nex.b = now.b - pour; nex.c = now.c; t = nex.a*10000+nex.b*100+nex.c; if(mp[t]==false){ q.push(nex); mp[t] = true; } } //b往c倒 pour = min(now.b, c-now.c); if(pour > 0){ nex.a = now.a; nex.b = now.b - pour; nex.c = now.c + pour; t = nex.a*10000+nex.b*100+nex.c; if(mp[t]==false){ q.push(nex); mp[t] = true; } } //c往a倒 pour = min(now.c, a-now.a); if(pour > 0){ nex.a = now.a + pour; nex.b = now.b; nex.c = now.c - pour; t = nex.a*10000+nex.b*100+nex.c; if(mp[t]==false){ q.push(nex); mp[t] = true; } } //c往b倒 pour = min(now.c, b-now.b); if(pour > 0){ nex.a = now.a; nex.b = now.b + pour; nex.c = now.c - pour; t = nex.a*10000+nex.b*100+nex.c; if(mp[t]==false){ q.push(nex); mp[t] = true; } } } return -1; //没有找到 } int main(){ while(cin>>a>>b>>c>>k){ if(k > a){ //测试用例没有涉及到这点,其实可以忽略 printf("no\n"); }else{ int ans = -1; mp.clear(); ans = BFS(); if(ans != -1) printf("yes\n%d\n", ans); else printf("no\n"); } } return 0; }