[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: }
/*
posted @ 2011-06-12 20:56  HappyAngel  阅读(1154)  评论(0编辑  收藏  举报