USACO-Section1.4 Mother's Milk

本文介绍了USACO中的一个题目,涉及容量为A、B、C的三个桶和深度优先搜索算法。通过模拟牛奶倒入过程,寻找当A桶为空时,C桶可能剩余的牛奶量。样例输入和输出展示了具体操作,题解部分解释了使用三维数组和递归策略解决此问题的方法。

2017-07-16

题目大意:

农民约翰有三个容量分别是A,B,C升的桶,A,B,C分别是三个从1到20的整数, 最初,A和B桶都是空的,而C桶是装满牛奶的。有时,农民把牛奶从一个桶倒到 另一个桶中,直到被灌桶装满或原桶空了。当然每一次灌注都是完全的。由于节约, 牛奶不会有丢失
写一个程序去帮助农民找出当A桶是空的时候,C桶中牛奶所剩量的所有可能性。

样例输入:

8 9 10

样例输出:

1 2 8 9 10

题解:

这一题是我第一次使用一个三维数组来标记状态,因为有A,B,C三个桶,所以是三维。使用深度优先搜索来实现,三个瓶子中不空的瓶子轮流往另外两个瓶子中倒入,又分为两种情况,第一是瓶子中已有的牛奶可以到满整个瓶子,第二种的瓶子中已有的牛奶倒不满瓶子。然后模拟倒牛奶的过程,结束一层递归后应该进行回溯,回溯到上一层的状态。递归终点是当A是空,C里面的牛奶没有记录过,就将C里面的牛奶值插入到Set集合中。

代码:
#include<iostream>
#include<fstream>
#include<set>
using namespace std;
pair<int , int> p[3];
set<int> s;
bool is_use[30];
bool is_visit[20][20][20];
void dfs(int a , int b , int c,int step){
    if(p[0].first == 0 && !is_use[p[2].first]){
        s.insert(p[2].first);
        is_use[p[2].first] = true;
    }
    if(step && is_visit[a][b][c])
        return ;
    is_visit[a][b][c] = true;
    for(int i = 0 ;i < 3;i++){  //即将倒的瓶子
        if(p[i].first == 0) continue;
        for(int j = 0;j < 3;j++){   //即将被倒的瓶子
            if(i != j){
                if(p[i].first >= p[j].second - p[j].first){ //倒不满
                    int temp = p[j].first;
                    p[i].first -= p[j].second - p[j].first;
                    p[j].first = p[j].second;
                    dfs(p[0].first ,p[1].first , p[2].first, step + 1);
                    p[j].first = temp;
                    p[i].first += p[j].second - p[j].first;
                }else if(p[i].first < p[j].second - p[j].first){ //不够倒
                    int temp = p[i].first;
                    p[j].first += p[i].first;
                    p[i].first = 0;
                    dfs(p[0].first ,p[1].first , p[2].first, step + 1);
                    p[i].first = temp;
                    p[j].first -= p[i].first;
                }
            }
        }
    }
    is_visit[a][b][c] = false;  //回溯
}

int main(){
    ofstream cout("milk3.out");
    ifstream cin("milk3.in");
    cin >> p[0].second >> p[1].second >> p[2].second;
    p[1].first = 0;
    p[2].first = 0;
    p[2].first = p[2].second;
    s.insert(p[2].first);
    is_use[p[2].first] = true;
    is_visit[0][0][p[2].first] = true;
    dfs(0 , 0 , p[2].first , 0);
    int len = s.size();
    int i = 0;
    for(set<int>::iterator it = s.begin() ; it != s.end(); it++,i++){
        cout << *it;
        if(i < len - 1) 
            cout << " "; //为了末尾没有空格
    }
    cout << endl;
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值