[USACO] 从Mother’s Milk看搜索
最近由于想锻炼小型程序编写能力,所以打算做完USACO,当然这个是比较水的题目,但对于业余ACM爱好
者的我来说还是有一定难度的,拿来练手和学习还是很不错的。
Mother’s Milk是一个搜索的题目,总的来说难度不大,但是我在一开始的时候并没有那么轻易的看出状
态的转移方式,在状态转移那里卡了很久,一直在想怎么模拟这个倒水的过程?其实我是陷入题目的误
区,明知道是到搜索题目,就应该以搜索的方式来思考,那么怎么思考搜索题目的解法呢?
首先,搜索的题目最重要的就是找到状态,就是怎么样一个东西算作此题的状态,亦即解空间的一个节
点,这是首要任务,如果连状态都没定义好,后续的一切都是浮云。
然后呢,就是要思考从一个状态有几种转移方式,就是从解空间的一个节点出发有条边和其他节点相连,
这样就能够大概估计到解空间的大小,以考虑是用深搜呢,还是广搜。如果空间需求不大,解可能在离根节
点较近的地方,就果断广搜,其他就深搜吧。我广搜一般是用队列,深搜是用递归实现的,这中间要考虑几点:
- 考虑用何种方式判重?(布尔数组?)
- 考虑是否可以剪枝?(例如USACO的 The Clocks要考虑到同一种类型的旋转转3次后会回到原点,
因此果断剪掉3次以上同类型旋转)
最后就是编码实现了,然后考虑各种优化问题,例如查找改成哈希等等。
用这种想法思考Mother’s milk, 考虑到状态就是 (A桶中牛奶的数量,B桶中牛奶的数量),因为牛奶的
总数量是确定的,所以上述序列足可确定一个解空间的节点。然后思考可以有几种转移方式?很明显,总共
三个桶,因此就是6种:A->B A->C B->A B->C C->A C->B。以A->B来说,这样转移之后状态是什么呢?A的
牛奶数应该是max(0, a+b-B),其中a,b是A和B桶中原来牛奶的数量,A,B是A和B桶的容量。B的牛奶数是
min(a+b, B),其他的以此类推。
估算一下解空间的大小吧,由于题目限制A,B,C的值是1-20之间,所以总共的状态,最多,也就
20*20=400,所以,用广搜就行。代码如下:
1: /*
2: ID:happyan33: PROG:milk34: LANG:C++5: */6:7: #include <iostream>8: #include <fstream>9: #include <queue>10: #include <vector>11: #include <algorithm>12: #include <cstring>13: #include <cstdlib>14: #include <bitset>15:16: using namespace std;17:18: struct state
19: {20: int a;
21: int b;
22: int c;
23: };24:25: const int num=21;26: bool bFlag[num][num];//判重27:28: //广搜
29: //pre: 输入a,b,c是 桶的容量
30: //post: 输出res,是 c的可能数,未排序
31: void GetAnswer(int a, int b, int c, vector<int>& res)32: {33: state init_state;34: init_state.a=0;35: init_state.b=0;36: init_state.c=c;37:38: queue<state> q;39: q.push(init_state);40: while(!q.empty())
41: {42: state s = q.front();43: q.pop();44: if(s.a>=0 && s.b>=0 && s.c>=0)
45: {46: if(s.a==0)
47: {48: if(res.end()==find(res.begin(),res.end(),s.c))
49: res.push_back(s.c);50: }51: bFlag[s.a][s.b]=true;
52: //all 6 possibilities
53:54: state temp = s;55: //1 a->b
56: s.a = max(0,s.a+s.b-b);57: s.b = min(temp.a+s.b,b);58: if(!bFlag[s.a][s.b])
59: q.push(s);60: s=temp;61:62: //2 a->c
63: s.a = max(0,s.a+s.c-c);64: s.c = min(temp.a+s.c,c);65: if(!bFlag[s.a][s.b])
66: q.push(s);67: s=temp;68:69: //3 b->a
70: s.b = max(0,s.b+s.a-a);71: s.a = min(temp.b+s.a,a);72: if(!bFlag[s.a][s.b])
73: q.push(s);74: s=temp;75:76: //4 b->c
77: s.b = max(0,s.b+s.c-c);78: s.c = min(temp.b+s.c,c);79: if(!bFlag[s.a][s.b])
80: q.push(s);81: s=temp;82:83: //5 c->b
84: s.c = max(0,s.c+s.b-b);85: s.b = min(temp.c+s.b,b);86: if(!bFlag[s.a][s.b])
87: q.push(s);88: s=temp;89:90: //6 c->a
91: s.c = max(0,s.c+s.a-a);92: s.a = min(temp.c+s.a,a);93: if(!bFlag[s.a][s.b])
94: q.push(s);95: s=temp;96: }97: }98: }99:100: int main(void)101: {102: ifstream fin;103: fin.open("milk3.in");
104: ofstream fout;105: fout.open("milk3.out");
106:107: int a=0;
108: int b=0;
109: int c=0;
110: fin>>a>>b>>c;111:112: for(int i=0; i < num; i++)113: {114: for(int j=0; j < num; j++)115: bFlag[i][j]=false;
116: }117:118: vector<int> res;
119:120: GetAnswer(a,b,c,res);121:122: sort(res.begin(),res.end());123: for(vector<int>::iterator it=res.begin(); it!=res.end()-1; it++)124: {125: fout<<(*it)<<" ";
126: }127:128: fout<<res.back()<<endl;129:130: fin.close();131: fout.close();132: //getchar();
133: //getchar();
134: //getchar();
135: return 0;
136: }
/*