USACO Training Section1.4 Mother's Milk

状态空间是ABC三个不大于20的整数,很小。状态转换条件也很清楚,作广度优先遍历即可。关键依然是如何记录状态。与clocks的方法类似,使用单个整数来记录状态,使用位操作来做基本操作。

事实上可以只记录两个筒的状态而不是三个,因为牛奶的总数是已知的。不过这样使得编程复杂度上升。

原题链接
http://ace.delos.com/usacoprob2?a=sagomFwQFqE&S=milk3

/*
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;
}

你可能感兴趣的:(编程,C++,c,C#)