[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:happyan3

  3: PROG:milk3

  4: 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: }
/*

你可能感兴趣的:(USACO)