USACO:1.4.4 Mother's Milk 母亲的牛奶 解析

探讨了如何使用广度优先搜索(BFS)算法解决母牛的牛奶问题,即找出在特定条件下,C桶中剩余牛奶量的所有可能性。介绍了算法的具体实现过程及代码示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1.4.4 Mother's Milk 母亲的牛奶
题目描述
农民约翰有三个容量分别是A,B,C 升的桶,A,B,C 分别是三个从1 到20 的整数,最初,A 和B 桶都是空的,而C 桶是装满牛奶的.有时,约翰把牛奶从一个桶倒到另一个桶中,直到被灌桶装满或原桶空了.当然每一次灌注都是完全的.由于节约,牛奶不会有丢失.

写一个程序去帮助约翰找出当A 桶是空的时候,C 桶中牛奶所剩量的所有可能性.

PROGRAM NAME: milk3

INPUT FORMAT

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

SAMPLE INPUT (file milk3.in)

8 9 10

OUTPUT FORMAT

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

SAMPLE OUTPUT (file milk3.out)

1 2 8 9 10

SAMPLE INPUT (file milk3.in)

2 5 10

SAMPLE OUTPUT (file milk3.out)

5 6 7 8 9 10

解题思路:

      首先声明,这个题目我没做出来!呜呜,真受打击,别灰心~

        通过请教大牛黄总和查阅网上资料,我发现常见的就是两种做法,DFS深度优先搜索和BFS广度优先搜索。DFS---常用堆栈实现,BFS---常用队列实现。我感觉都一样,都是枚举,都必须枚举所有可能的结果。关键是都要记录当前状态,记录所有状态,不断的搜索下一状态和回溯上一状态。。。

       从初始状态开始,倒牛奶。。。每次只能有6种选择,a倒b,a倒c,b倒a,b倒c,c倒a,c倒b。用一个数组vis[i][j][k]判重,s[i]记录c中所有可能值(s[i]=true表示c中可能出现i),最后输出s中所有true的就可以了。

<span style="font-size:14px;">/*
ID:大牛黄总
LANG:C++
TASK:milk3
*/
#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
using namespace std;

int cot[25];
int min(int a,int b)
{
    return a>b?b:a;
}

int main()
{
    FILE *fin,*fout;
    fin=fopen("milk3.in","r");
    fout=fopen("milk3.out","w");
    int a,b,c;
    fscanf(fin,"%d %d %d",&a,&b,&c);

    int vis[25][25][25];// 状态标志
    memset(vis,0,sizeof(vis));

    queue<int> q1,q2,q3;  //定义了3个队列
    vis[0][0][c]=1;

    memset(cot,0,sizeof(cot));

    q1.push(0);q2.push(0);q3.push(c);
    int t1,t2,t3,pour,aa,bb,cc;

    while(!q1.empty())//队列1不为空时
    {
        t1=q1.front();t2=q2.front();t3=q3.front();

        q1.pop();q2.pop();q3.pop();

        if(t1==0&&!cot[t3]) //A为空,且C有新的牛奶量
			cot[t3]=1;
        //从A倒入B
        if(t1!=0&&t2!=b)//A不为空,B不满;---能倒
        {
            pour=min(b-t2,t1);
            aa=t1-pour;
            bb=t2+pour;
            cc=t3;
            if(!vis[aa][bb][cc])
            {q1.push(aa);q2.push(bb);q3.push(cc);vis[aa][bb][cc]=1;}
        }
        //从A倒入C
        if(t1!=0&&t3!=c)
        {
            pour=min(c-t3,t1);
            aa=t1-pour;
            bb=t2;
            cc=t3+pour;
            if(!vis[aa][bb][cc])
            {q1.push(aa);q2.push(bb);q3.push(cc);vis[aa][bb][cc]=1;}
		}
        //从B倒入A
        if(t2!=0&&t1!=a)
        {
            pour=min(a-t1,t2);
            aa=t1+pour;
            bb=t2-pour;
            cc=t3;
            if(!vis[aa][bb][cc])
            {q1.push(aa);q2.push(bb);q3.push(cc);vis[aa][bb][cc]=1;}
        }
        //从B倒入C
        if(t2!=0&&t3!=c)
        {
            pour=min(t2,c-t3);
            aa=t1;
            bb=t2-pour;
            cc=t3+pour;
            if(!vis[aa][bb][cc])
            {q1.push(aa);q2.push(bb);q3.push(cc);vis[aa][bb][cc]=1;}
        }
        //从C倒入A
        if(t3!=0&&t1!=a)
        {
            pour=min(t3,a-t1);
            aa=t1+pour;
            bb=t2;
            cc=t3-pour;
            if(!vis[aa][bb][cc])
            {q1.push(aa);q2.push(bb);q3.push(cc);vis[aa][bb][cc]=1;}
        }
        //从C倒入B
        if(t3!=0&&t2!=b)
        {
            pour=min(t3,b-t2);
            aa=t1;
            bb=t2+pour;
            cc=t3-pour;
            if(!vis[aa][bb][cc])
            {q1.push(aa);q2.push(bb);q3.push(cc);vis[aa][bb][cc]=1;}
        }

    }

	int flag=1;
    for(int i=0;i<21;i++)
    {
		if(cot[i]&&flag)
		{
			fprintf(stdout,"%d",i);flag=0;
		}
		else if(cot[i])
			fprintf(stdout," %d",i);
	}
    fprintf(stdout,"\n");
    return 0;
}




// USACO's code.
// Russ Cox
// We use a simple depth-first search to find all the possible states for the three buckets, 
// pruning the search by not researching from states we've seen before.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <ctype.h>

#define MAX 20

typedef struct State	State;
struct State {
    int a[3];
};

int seen[MAX+1][MAX+1][MAX+1];
int canget[MAX+1];

State state(int a, int b, int c)//???
{
    State s;
	
    s.a[0] = a;
    s.a[1] = b;
    s.a[2] = c;
    return s;
}

int cap[3];

/* pour from bucket "from" to bucket "to" */
State
pour(State s, int from, int to)
{
    int amt;
	
    amt = s.a[from];
    if(s.a[to]+amt > cap[to])
		amt = cap[to] - s.a[to];
	
    s.a[from] -= amt;//
    s.a[to] += amt;
    return s;
}
//---------------
void
search(State s)
{
    int i, j; 
	
    if(seen[s.a[0]][s.a[1]][s.a[2]])
		return;
	 
    seen[s.a[0]][s.a[1]][s.a[2]] = 1;
	
    if(s.a[0] == 0)	  /* bucket A empty */
		canget[s.a[2]] = 1;
	
    for(i=0; i<3; i++)
		for(j=0; j<3; j++)
			if(i!=j)
			search(pour(s, i, j));	
}

void
main(void)
{
    int i;
    FILE *fin, *fout;
    char *sep;
	
    fin = fopen("milk3.in", "r");
    fout = fopen("milk3.out", "w");
    assert(fin != NULL && fout != NULL);
	
    fscanf(fin, "%d %d %d", &cap[0], &cap[1], &cap[2]);
	
    search(state(0, 0, cap[2]));//从初始状态开始搜索 search from original state
	
    sep = "";
    for(i=0; i<=cap[2]; i++) {
		if(canget[i]) {
			fprintf(stdout, "%s%d", sep, i);
			sep = " ";
		}
    }
    //fprintf(stdout, "\n");
	
    exit(0);
}
</span>
   由于自身是初学者,编程能力有限,未达到专业程序员的水平,可能误导大家,请大家甄读;文字编辑也一般,文中会有措辞不当。博文中的错误和不足敬请读者批评指正。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

蓝亦

感谢博主辛勤的付出

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值