水题(原 USACO Mother's Milk)
【题目描述】
可达鸭自从小霞旅行回来后一直没有什么事做(准确来说旅行的时候也是),所以它开始思考一些令人头疼的问题,以使自己能在道馆战中,展现自己真正的实力。今天它面对这样一个问题:面前有三个水杯,容量分别分别为a,b,c(下文用容量代指杯子),一开始c中装满了水,可以将杯子1里的水灌入杯子2灌注的过程中,如果杯子1的水量大于杯子2的剩余容量,那么只会将杯子2灌满,杯子1中任然会有剩余的水;如果小于则杯子1中的水全部灌入杯子2,可达鸭思考着当杯子a空着时,达到杯子c每种可能的水量最少需要几次操作,但是它在这一点上并不需要你帮忙,只是它比较懒,不愿意思考那些不可能的情况,所以它需要你告诉它当杯子a空着时杯子c中所有可能的水量。
【题目输入】
仅一行,为3个正整数a,b,c表示3个杯子的容量
【题目输出】
仅一行,升序输出所有可能
【样例输入1】
8 9 10
【样例输出1】
1 2 8 9 10
【样例输入2】
2 5 10
【样例输出2】
5 6 7 8 9 10
【数据范围与提示】
a,b,c<=20
题如其名是道水题
学长考试第一题,我并不觉得是水题(至少我题目都没明白),还是自己功力不够,训练懈怠
思路:
这种倒水的搜索题还是很典型的,把初始的容量用 v[ ] 储存上,再把刚开始 st.v(0,0,c) 拉进来广搜
广搜部分:
- 两层循环枚举出各种倒水的情况
- 当倒出桶为0,或倒入桶已满已经没意义,就不再考虑,continue
- 计算出要倒的水量: int pour=min(cur.v[i]+cur.v[j],v[j])-cur.v[j];这行精炼的代码完全解释了题意,大白话来说:“能倒完倒完,倒不完倒满”。怎么做到的呢?如果“倒出桶”当前的水 加上 “倒入桶”当前的水小于“倒入桶”的限度,那就给倒完,如果超过了“倒入桶”的最大限度,那就倒入剩余容量的水,给倒满
每有一种情况,判断是否已有,我们用一个三维的 vis[ next.v[1] ][ next.v[2] ][ next.v[3] ] 来记录,因为数据量很小,开三维毫无问题
代码
#include<stdio.h> #include<algorithm> #include<queue> using namespace std; int v[4],ans[1001],cnt; bool vis[21][21][21]; struct node { int v[4],step; }; queue<node> q; void bfs() { node st; st.v[1]=0,st.v[2]=0,st.v[3]=v[3]; q.push(st); while(!q.empty()) { node cur=q.front(); q.pop(); if(cur.v[1]==0) { ans[++cnt]=cur.v[3]; } for(int i=1;i<=3;++i) //from for(int j=1;j<=3;++j) //to { if(cur.v[i]==0 || cur.v[j]==v[j]) continue; node next=cur; int pour=min(cur.v[i]+cur.v[j],v[j])-cur.v[j]; next.v[i]-=pour; next.v[j]+=pour; next.step=cur.step+1; if(!vis[next.v[1]][next.v[2]][next.v[3]]) { vis[next.v[1]][next.v[2]][next.v[3]]=1; q.push(next); } } } } int main() { for(int i=1;i<=3;++i) scanf("%d",&v[i]); vis[0][0][v[3]]=1; bfs(); sort(ans+1,ans+1+cnt); for(int i=1;i<=cnt;++i) printf("%d ",ans[i]); return 0; }
从0到1很难,但从1到100很容易