USACO1.4.4 Mother's Mil 母亲的牛奶 题解报告(dfs)

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

Input
单独的一行包括三个整数A,B和C。

Output
只有一行,列出当A桶是空的时候,C桶牛奶所剩量的所有可能性。

Sample Input
8 9 10
Sample Output
1 2 8 9 10

倒水总共6种状态,分别为

  • A->B
  • B->A
  • A->C
  • C->A
  • B->C
  • C->B
    记杯子i容量为 vi v i ,杯子内所含水为 wi w i ;
    所以我们记录每一次 A A B C C w(其实只需要记录2个杯子即可,任意2个杯子 w w 确定了那么第3个杯子的w),然后对以上6种情况进行遍历,如果碰见当前 w0,w1,w2 w 0 , w 1 , w 2 的组合未被标记,则以当前 w0,w1,w2 w 0 , w 1 , w 2 标记并以其为起点进行深搜,这样就能求出任意两个杯子相互倒水的所有情况了。然后取 w0=0 w 0 = 0 的时候 w2 w 2 的值即可
    AC代码如下
#include <map>
#include <cstdlib>
#include <cmath>
#include <cstdio>
#include <string>
#include <cstring>
#include <fstream>
#include <iostream>
#include <algorithm>
#define fori(a) for(int i=0;i<a;i++)
#define forj(a) for(int j=0;j<a;j++)
#define ifor(a) for(int i=1;i<=a;i++)
#define jfor(a) for(int j=1;j<=a;j++)
#define IO do{\
    ios::sync_with_stdio(false);\
    cin.tie(0);\
    cout.tie(0);}while(0)

#define mp(a,b) make_pair(a,b)
using namespace std;
typedef long long ll;
const int maxn =  210;

map <pair<int,int>,bool>q; //标记三个杯子中的当前容量是否已经遍历过,避免重复搜索
pair <int,int >buf;
map <int,bool>res;          
int cnt;
int ans[maxn];
int dir[6][2]= {{0,2},{0,2},{1,2},{1,0},{2,0},{2,1}};//从dir[i][0]往dir[i][1]中倒水
int v[3]; //每个杯子的容量
int w[3]; //每个杯子已经装了多少水
int push(int a,int b) {return min(w[a],v[b]-w[b]);} //a向b中倒水的量
void dfs() {
    if(w[0]==0&&!res[w[2]]) {   //如果A为0且C中的容量未被记录
        ans[cnt++] = w[2];
        res[w[2]] = true;
    }
    fori(6) {
        int val = push(dir[i][0],dir[i][1]);
        if(val) {
            //倒水操作
            int a = dir[i][0];
            int b = dir[i][1];
            w[a] -= val;
            w[b] += val;
            //*********//

            buf = mp(w[0],w[1]);
            if(!q[buf]) {         //如果这个结果未曾被遍历,则进入,继续dfs
                q[buf] = true;
                dfs();
            }
            w[a] += val;
            w[b] -= val;
        }

    }
}
int main() {
    fori(3)
    cin >> v[i];
    w[2] = v[2];
    dfs();
    sort(ans,ans+cnt);
    fori(cnt){
        if(i)
            cout <<" ";
        cout << ans[i];
    }
    cout << endl;
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值