写一个程序去帮助约翰找出当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 10SAMPLE 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>
由于自身是初学者,编程能力有限,未达到专业程序员的水平,可能误导大家,请大家甄读;文字编辑也一般,文中会有措辞不当。博文中的错误和不足敬请读者批评指正。