状态空间是ABC三个不大于20的整数,很小。状态转换条件也很清楚,作广度优先遍历即可。关键依然是如何记录状态。与clocks的方法类似,使用单个整数来记录状态,使用位操作来做基本操作。
事实上可以只记录两个筒的状态而不是三个,因为牛奶的总数是已知的。不过这样使得编程复杂度上升。
原题链接
[url]http://ace.delos.com/usacoprob2?a=sagomFwQFqE&S=milk3[/url]
事实上可以只记录两个筒的状态而不是三个,因为牛奶的总数是已知的。不过这样使得编程复杂度上升。
原题链接
[url]http://ace.delos.com/usacoprob2?a=sagomFwQFqE&S=milk3[/url]
/*
ID: blackco3
TASK: milk3
LANG: C++
*/
#include <fstream>
#include <memory.h>
#define _max_state_ 1<<15
#define _max_cap_ 32
using namespace std;
int cap[3];
int visited[_max_state_], queue[_max_state_] ;
inline int trans( int org, int from, int to )
{
int tmp[3]={ org&0x1f, (org>>5)&0x1f, (org>>10)&0x1f };
if( tmp[from]==0 || tmp[to]==cap[to] )
return org ;
if( tmp[from]>cap[to]-tmp[to] )
tmp[from] -= cap[to]-tmp[to], tmp[to]=cap[to] ;
else
tmp[to] += tmp[from], tmp[from]=0 ;
return tmp[0] | (tmp[1]<<5) | (tmp[2]<<10) ;
}
int main()
{
int base ;
ifstream fin("milk3.in");
fin >> cap[0] >> cap[1] >> cap[2] ;
int c_remain[_max_cap_];
memset(c_remain, 0, sizeof(c_remain) );
int *head=queue, *tail=queue ;
*(tail++)=(cap[2]<<10), visited[*head]=1, c_remain[cap[2]]=1 ;
register int nstate ;
do{
for( int from=0; from<3; from++ ){
for( int to=0; to<3; to++){
if(from==to)
continue ;
nstate=trans(*head, from, to);
if( visited[nstate] )
continue ;
visited[nstate]=1 ;
*(tail++)=nstate ;
if( !(nstate&0x1f) ){
c_remain[ (nstate>>10)&0x1f ]=1 ;
}
}
}
}while((++head)!=tail);
ofstream fout("milk3.out");
for(int i=0, first=1 ; i<=cap[2]; i++){
if( c_remain[i] ){
if( !first )
fout << " ";
fout << i ;
first=0 ;
}
}
fout << endl ;
return 0;
}