【USACO】milk3

倒牛奶的问题, 开始看感觉跟倒水的问题很像, 想直接找规律, 写个类似于循环取余的代码。
但后来发现不行,因为这道题有三个桶,水量也是有限制的。只好用模拟的方法把所有的情况都试一遍。

建一个state[21][21][21]的数组存储出现过的状态。对于遍历状态,对每一种状态,
分别采用六种处理方法,若有新状态出现这将新状态置为1,同时标记flag++;若所有循环之后,flag == 0, 就说明遍历完成了。

开始脑子抽筋了, 写了个多出口的程序, 显然是错的。如下:


int mothersmilk(int a, int b, int c)
{
int aa, bb, cc;
int flag = 0;

aa = a, bb = b, cc = c;
pour(&aa, A, &bb, B);
if(state[aa][bb][cc] != 1)
{
state[aa][bb][cc] = 1;
mothersmilk(aa, bb, cc); //
flag++;
}

aa = a, bb = b, cc = c;
pour(&bb, B, &aa, A);
if(state[aa][bb][cc] != 1)
{
state[aa][bb][cc] = 1;
mothersmilk(aa, bb, cc);
}

aa = a, bb = b, cc = c;
pour(&aa, A, &cc, C);
if(state[aa][bb][cc] != 1)
{
state[aa][bb][cc] = 1;
mothersmilk(aa, bb, cc); //
}

aa = a, bb = b, cc = c;
pour(&cc, C, &aa, A);
if(state[aa][bb][cc] != 1)
{
state[aa][bb][cc] = 1;
mothersmilk(aa, bb, cc);
}

aa = a, bb = b, cc = c;
pour(&bb, B, &cc, C);
if(state[aa][bb][cc] != 1)
{
state[aa][bb][cc] = 1;
mothersmilk(aa, bb, cc); //
}

aa = a, bb = b, cc = c;
pour(&cc, C, &bb, B);
if(state[aa][bb][cc] != 1)
{
state[aa][bb][cc] = 1;
mothersmilk(aa, bb, cc); //
}
  return 0;
//...
}

错误的原因在于,若是第一个if语句中的mothersmilk操作完了,一定会返回0,那后面的语句都起不到作用了。

后来发现,可以直接对所有的state变量循环,用for语句,逻辑就清楚多了,提交也AC了。正确的代码:


/*
ID: 13012131
LANG: C
TASK: milk3
*/

#include <stdio.h>
#include <assert.h>

int state[21][21][21]; //存储状态 出现过为1 未出现过为0
int A, B, C;

int pour(int *a, int fulla, int *b, int fullb) //a向b倒水
{
if(*b == fullb || *a == 0) //若a没水 或 b满 a不能向b倒水 状态不变
{
return 1;
}
if(*b != fullb) //b不满
{
if(*a <= fullb - *b) //a倒光
{
*b = *b + *a;
*a = 0;
}
else //b倒满
{
*a = *a - (fullb - *b);
*b = fullb;
}
}
return 0;
}

int main()
{
FILE *in, *out;
in = fopen("milk3.in", "r");
out = fopen("milk3.out", "w");
int ans[21] = {0};
int i, j ,k;

fscanf(in, "%d %d %d", &A, &B, &C);

for(i = 0; i <= 20; i++)
{
for(j = 0; j <= 20; j++)
{
for(k = 0; k <= 20; k++)
{
state[i][j][k] = 0;
}
}
}
state[0][0][C] = 1;

int flag = 0;
do{
flag = 0; //注意:flag一定要写在这里 因为在扩展过程中,需要对state的所有状态循环多次 以防止在大序号状态下扩展了小序号状态 比如 2 0 8 扩展为 0 2 8 因为0 2 8的状态已经超过了 所以还要重新遍历一遍才可以
for(i = 0; i <= A; i++)
{
for(j = 0; j <= B; j++)
{
for(k = 0; k <= C; k++)
{
if(state[i][j][k] == 1)
{
int aa, bb, cc;
aa = i, bb = j, cc = k;
pour(&aa, A, &bb, B);
if(state[aa][bb][cc] == 0)
{
state[aa][bb][cc] = 1;
flag++;
}

aa = i, bb = j, cc = k;
pour(&bb, B, &aa, A);
if(state[aa][bb][cc] == 0)
{
state[aa][bb][cc] = 1;
flag++;
}

aa = i, bb = j, cc = k;
pour(&aa, A, &cc, C);
if(state[aa][bb][cc] == 0)
{
state[aa][bb][cc] = 1;
flag++;
}

aa = i, bb = j, cc = k;
pour(&cc, C, &aa, A);
if(state[aa][bb][cc] == 0)
{
state[aa][bb][cc] = 1;
flag++;
}

aa = i, bb = j, cc = k;
pour(&bb, B, &cc, C);
if(state[aa][bb][cc] == 0)
{
state[aa][bb][cc] = 1;
flag++;
}

aa = i, bb = j, cc = k;
pour(&cc, C, &bb, B);
if(state[aa][bb][cc] == 0)
{
state[aa][bb][cc] = 1;
flag++;
}
state[i][j][k]++;
}

}
}
}
}while(flag > 0);

for(j = 0; j <= 20; j++)
{
for(k = 0; k <= 20; k++)
{
if(state[0][j][k] != 0 && ans[k] == 0)
{
ans[k] = 1;
}
}
}

for(i = 0; i < C; i++)
{
if(ans[i] == 1)
{
fprintf(out, "%d ", i);
}
}
fprintf(out, "%d\n", C);

return 0;
}

【USACO】milk3,布布扣,bubuko.com

时间: 2024-11-24 16:45:34

【USACO】milk3的相关文章

【USACO】Mother&#39;s Milk(搜索)

一开始还在想去重的问题,结果发现后台数据貌似没有重复的情况= = /* ID: 18906421 LANG: C++ PROG: milk3 */ #include<cmath> #include<cstdio> #include<vector> #include<algorithm> using namespace std; const int maxn = 25; int vis[maxn][maxn][maxn] = {0}; vector<in

【USACO】checker

一看题目 经典的8皇后问题 不过是皇后数量可变而已 不用想 回溯法. 需要个生成每次可选择序列的函数, 在存储可选择的序列时按照先大后小的顺序排的.这样每次找最小和去掉最小都很方便,只要有个记录数量的变量 每次减1就好了.  写完后,居然悲剧了. 在皇后数量达到13时, 在自己电脑上跑 内存溢出了 在评分系统上超时了.需要优化. #include <stdio.h> //k计算第几层从0开始 x已经摆好的位置 S存放产生的位置 l存放产生的数量 N一共有多少位置可以选择 int calcula

【USACO】calfflac

关键:以回文中心位置为变量进行遍历 //必须把纯字母先提出来 否则肯能会出现错误 比如: lvlv= 在检查长度4时 lvlv认为不是回文 vlv=认为是回文 但实际上 lvl 出现的要更早一些 //判断回文的方法 可以输入字符串后 左右比较 或者分别正序 逆序 存储 判断是否相等 //我的思路不对 严重超时了 我是以长度为变量进行循环 对于每个长度 每一个不同起始点的序列都需要对 整个序列重新判断一次是否为回文 O(n^3) //答案中 以中心字母为变量进行循环 只需要对每一个字母做为中心变量

【USACO】第一章总结

做了大半个月,终于把第一章做完了 有的题遇到了不小的坎儿,看着网上一群高中生都做得那么好,心理还是有些小郁闷的.不禁感慨我过去的四年真是虚度啊.总结一下第一章学习到的知识吧. ①闰年判断 int isleapyear(int N) { if((N%100 != 0 && N%4 ==0) || (N%400 == 0)) return 1; else return 0; } 计算闰年日期时可以用两个数组存放每个月的时间 int Year[12] = {31, 28, 31, 30, 31,

【USACO】Transformations

A square pattern of size N x N (1 <= N <= 10) black and white square tiles is transformed into another square pattern. Write a program that will recognize the minimum transformation that has been applied to the original pattern given the following l

【USACO】奶牛跑步2

P1443 - [USACO]奶牛跑步2 Description FJ的N(1 <= N <= 100,000)头奶牛们又兴高采烈地出来运动了!她们在一条无限长的小路上跑步,每头牛起跑的位置都不同,速度也不尽相同. 道路中划出了若干条跑道,以便她们能快速"超车",同一跑道中的任意两头牛都不会出现在相同的位置.不过FJ不愿让任何一头牛更换跑道或者调整速度,他想 知道如果让牛们跑足T(1 <= T <= 1,000,000,000)分钟的话,至少需要多少条跑道才能满

【USACO】beads

题目: You have a necklace of N red, white, or blue beads (3<=N<=350) some of which are red, others blue, and others white, arranged at random. Here are two examples for n=29: 1 2 1 2 r b b r b r r b r b b b r r b r r r w r b r w w b b r r b b b b b b

【USACO】ariprog

输入 : N  M 要找到长度为 N 的等差数列,要求数列中每个数字都可以表达成 a^2 + b^2 的和, 数字大小不超过M^2 + M^2 输出: 等差数列首元素 间隔 (多组答案分行输出) 解题思路:因为等差数列的数字都是平房和数  所以先生成所有的 从0 - M^2 + M^2的平方和数 去掉相同的并从小到大排序 然后对 所有间隔 . 首元素 做循环 判断能否找到以该首元素和间隔为条件的其他N-1个需要的数字 可以就存成答案: 提交后超时了.... test 5的时候 超了5s 正在想简

【USACO】草地排水

Drainage Ditches 草地排水 usaco 4.2.1描述在农夫约翰的农场上,每逢下雨,Bessie最喜欢的三叶草地就积聚了一潭水.这意味着草地被水淹没了,并且小草要继续生长还要花相当长一段时间.因此,农夫约翰修建了一套排水系统来使贝茜的草地免除被大水淹没的烦恼(不用担心,雨水会流向附近的一条小溪).作为一名一流的技师,农夫约翰已经在每条排水沟的一端安上了控制器,这样他可以控制流入排水沟的水流量.农夫约翰知道每一条排水沟每分钟可以流过的水量,和排水系统的准确布局(起点为水潭而终点为小