5,530
社区成员




#include <stdio.h>
#include <string.h>
/*
* The Question:
*
*一座楼里没有楼梯,只有一架电梯,电梯一次最多只能乘3人,已知楼共有20层,每层有一个人,
每个人都有1~20中唯一的编号,他们要去对应的楼层。电梯初始状态:在一楼。目标状态:每个人在相应楼层。
试编写一个算法,完成目标状态,而且使电梯移动最小距离。
*
* ZhanZongru(Z80_AT_whut.edu.cn)
* 2009,May,30th
*
* For the sake of simpliticy.
*
* The Building uses a United Kingdom Floor naming fashion.
* 0-19 Floors.
* The people in every floor use a United States naming fashion to express their destinations.
* 1-20 Floors.
*
* In one words, 20 Americans in a UK building...
*/
/*Every floor can content 1 to 20 person.*/
unsigned char FloorContent[20][20];
/*The carrier struct.*/
typedef struct _Carrier{
unsigned char Position_uk;
unsigned char Passager_us[3];
}Carrier;
#define CAR_CAP 3
Carrier theCar;
typedef enum _CurrentDirect{
UP_WARD = 0,
DOWN_WARD
}CurDir;
CurDir theDir = UP_WARD;
unsigned char cur_bottom = 0;
unsigned char cur_top = 19;
unsigned char IsSuccessed = 0;
unsigned long RunFloorCount = 0;
void Run_One_Floor(void);
void LayToFloor(unsigned char pos_uk, unsigned char set_id);
void LoadToCar_Up(unsigned char floor_uk, unsigned char id);
void LoadToCar_Down(unsigned char floor_uk, unsigned char id);
unsigned char JudgeStatus();
unsigned char FloorSize(unsigned char floor_uk);
void ReCalc_Bot_Top(void);
void Show_Status(void);
unsigned char FloorFirstOne(unsigned char floor_uk);
unsigned char Min_Passger_id(void);
unsigned char Max_Passger_id(void);
int main(int argc, char** argv)
{
char input_file[50];
char output_file[50];
FILE* fp=NULL;
int i=0;
int simple_crc=0;
if(argc==1)
{
strcpy(input_file, "input.txt");
strcpy(output_file, "output.txt");
}
else if(argc==2)
{
strcpy(input_file, argv[1]);
strcpy(output_file, "output.txt");
}
else if(argc>=3)
{
strcpy(input_file, argv[1]);
strcpy(output_file, argv[2]);
}
else
{
}
fp = fopen(input_file, "r");
if(fp==NULL)
{
perror("Failed:fopen the input file\r\n");
return -1;
}
/*Read in the initial status, the status could generated by another program, now by hand editing.*/
for(i=0;i<20;i++)
{
fscanf(fp, "%d", (int*)&FloorContent[i][0]);
simple_crc+=FloorContent[i][0];
}
fclose(fp);
/*A very simple check to ensure 20 numbers are different.*/
if(simple_crc!=210)
{
}
/*The carrier initialiy stop at the bottom.*/
theCar.Position_uk = 0;
theCar.Passager_us[0] = 0;
theCar.Passager_us[1] = 0;
theCar.Passager_us[2] = 0;
/*It is the main loop, after run every floor, check whether completed.*/
while(!IsSuccessed)
{
#ifdef _DEBUG
Show_Status();
system("pause");
#endif
Run_One_Floor();
}
printf("Success %ld Times\r\n", RunFloorCount);
fp=fopen(output_file, "w");
for(i=0;i<20;i++)
{
fprintf(fp, "%d ",FloorFirstOne(i));
}
fclose(fp);
return 0;
}
/*For debug*/
void Show_Status(void)
{
int i,j=0;
for(i=0;i<20;i++)
{
printf("Floor%d: ",19-i);
for(j=0;j<20;j++)
{
printf(" %02d ", FloorContent[19-i][j]);
}
printf("\r\n");
}
printf("The Car status: %02d, %02d, %02d, %02d, %c\r\n",
theCar.Position_uk, theCar.Passager_us[0], theCar.Passager_us[1], theCar.Passager_us[2],
theDir==UP_WARD? '^':'v');
}
void Run_One_Floor(void)
{
int i=0;
//First decite the run direction of the car
if(theCar.Position_uk==cur_bottom)
{
theDir = UP_WARD;
ReCalc_Bot_Top();
}
if(theCar.Position_uk==cur_top)
{
theDir = DOWN_WARD;
ReCalc_Bot_Top();
}
//To see whether need to lay down someone whose destination is this floor
if(theCar.Passager_us[0]==(1+theCar.Position_uk))
{
LayToFloor(theCar.Position_uk, 0);
}
if(theCar.Passager_us[1]==(1+theCar.Position_uk))
{
LayToFloor(theCar.Position_uk, 1);
}
if(theCar.Passager_us[2]==(1+theCar.Position_uk))
{
LayToFloor(theCar.Position_uk, 2);
}
//Fill the carrier if it has some empty space,or swap when worthy
for(i=0;i<20;i++)
{
if( (FloorContent[theCar.Position_uk][i]>(theCar.Position_uk+1)) && (theDir == UP_WARD) )
{
LoadToCar_Up(theCar.Position_uk,i);
}
if((FloorContent[theCar.Position_uk][i]!=0) &&
(FloorContent[theCar.Position_uk][i]<(theCar.Position_uk+1)) && (theDir == DOWN_WARD) )
{
LoadToCar_Down(theCar.Position_uk,i);
}
}
//Advance a floor
if(theDir == UP_WARD)
{
IsSuccessed = JudgeStatus();
if(!IsSuccessed)
{
theCar.Position_uk+=1;
RunFloorCount++;
}
}
else if(theDir == DOWN_WARD)
{
IsSuccessed = JudgeStatus();
if(!IsSuccessed)
{
theCar.Position_uk-=1;
RunFloorCount++;
}
}
else
{
printf("theDir is error\r\n");
return ;
}
}
unsigned char JudgeStatus()
{
int i = 0;
for(i=0; i<20; i++)
{
if( (FloorSize(i)!=1) || (FloorFirstOne(i)!=(i+1)) )
return 0;
}
return 1;
}
/* Return the first person's destination in one floor.*/
unsigned char FloorFirstOne(unsigned char floor_uk)
{
int i=0;
for(i=0;i<20;i++)
{
if(FloorContent[floor_uk][i]!=0)
{
return FloorContent[floor_uk][i];
}
}
return 0;
}
/*return the number of persons in one floor.*/
unsigned char FloorSize(unsigned char floor_uk)
{
int i = 0;
int j = 0;
for(i=0; i<20; i++)
{
if(0==FloorContent[floor_uk][i])
continue;
j++;
}
return j;
}
/* Re-calculate the current bottom and top floors.*/
void ReCalc_Bot_Top(void)
{
#if 1
int i=0;
if(theDir==UP_WARD)
{
for(i=19;i>=0;i--)
{
if((FloorSize(i)!=1) || (FloorFirstOne(i)!=i+1))
{
cur_top = i;
break;
}
}
}
else if(theDir==DOWN_WARD)
{
for(i=0;i<20;i++)
{
if((FloorSize(i)!=1) || (FloorFirstOne(i)!=i+1))
{
cur_bottom = i;
break;
}
}
}
else
{
}
#endif
}
/* Lay a person from the carrier to the floor.*/
void LayToFloor(unsigned char pos_uk, unsigned char set_id)
{
int i=0;
for(i=0; i<20; i++)
{//Find a empty space to lay down the passager
if(FloorContent[pos_uk][i]==0)
{
FloorContent[pos_uk][i] = theCar.Passager_us[set_id];
theCar.Passager_us[set_id] = 0;
break;
}
}
return;
}
/* When the direction is UPWARD, load a person from the floor to the carrier.*/
void LoadToCar_Up(unsigned char floor_uk, unsigned char id)
{
int i=0;
unsigned char temp=0;
//Find a empty sit set to load the passager
if(theCar.Passager_us[0]==0)
{
#ifdef _DEBUG
printf("the empty set is 0\r\n");
#endif
theCar.Passager_us[0] = FloorContent[floor_uk][id];
FloorContent[floor_uk][id] = 0;
}
else if(theCar.Passager_us[1]==0)
{
#ifdef _DEBUG
printf("the empty set is 1\r\n");
#endif
theCar.Passager_us[1] = FloorContent[floor_uk][id];
FloorContent[floor_uk][id] = 0;
}
else if(theCar.Passager_us[2]==0)
{
#ifdef _DEBUG
printf("the empty set is 2\r\n");
#endif
theCar.Passager_us[2] = FloorContent[floor_uk][id];
FloorContent[floor_uk][id] = 0;
}
else
{//Full, swap if wothy
#ifdef _DEBUG
printf("up swap fig, Min_ID is %d\r\n", Min_Passger_id());
#endif
if(FloorContent[floor_uk][id]>theCar.Passager_us[Min_Passger_id()])
{
temp = FloorContent[floor_uk][id];
FloorContent[floor_uk][id] = theCar.Passager_us[Min_Passger_id()];
theCar.Passager_us[Min_Passger_id()] = temp;
}
}
return;
}
/* return the minium passager's destination in the carrier.*/
unsigned char Min_Passger_id(void)
{
unsigned char min_id = 0;
if(theCar.Passager_us[1]<theCar.Passager_us[min_id])
min_id = 1;
if(theCar.Passager_us[2]<theCar.Passager_us[min_id])
min_id = 2;
return min_id;
}
/* return the maxium passager's destination in the carrier.*/
unsigned char Max_Passger_id(void)
{
unsigned char max_id = 0;
if(theCar.Passager_us[1]>theCar.Passager_us[max_id])
max_id = 1;
if(theCar.Passager_us[2]>theCar.Passager_us[max_id])
max_id = 2;
return max_id;
}
/* When the direction is DOWNWARD, load a person from the floor to the carrier.*/
void LoadToCar_Down(unsigned char floor_uk, unsigned char id)
{
int i=0;
unsigned char temp=0;
//Find a empty sit set to load the passager
if(theCar.Passager_us[0]==0)
{
theCar.Passager_us[0] = FloorContent[floor_uk][id];
FloorContent[floor_uk][id] = 0;
}
else if(theCar.Passager_us[1]==0)
{
theCar.Passager_us[1] = FloorContent[floor_uk][id];
FloorContent[floor_uk][id] = 0;
}
else if(theCar.Passager_us[2]==0)
{
theCar.Passager_us[2] = FloorContent[floor_uk][id];
FloorContent[floor_uk][id] = 0;
}
else
{//Full, swap if wothy
if(FloorContent[floor_uk][id]<theCar.Passager_us[Max_Passger_id()])
{
temp = FloorContent[floor_uk][id];
FloorContent[floor_uk][id] = theCar.Passager_us[Max_Passger_id()];
theCar.Passager_us[Max_Passger_id()] = temp;
}
}
return;
}
void AddStatus_2(const CLift & lift,__Policy & status,__History & history)
{
typedef std::pair<__History::iterator,bool> __RetType;
__RetType ret = history.insert(lift);
if(ret.second){
int c1 = status.empty() ? 0 : status.front().FinishCount();
int c2 = lift.FinishCount();
bool push = false;
if(c1 < c2 - MAX_C){
#if __STATISTICS
add_reduced += status.size();
#endif
status.clear();
push = true;
}else if (c1 <= c2 + MAX_C)
push = true;
#if __STATISTICS
else
++add_reduced;
#endif
if(push)
status.push_back(lift);
if(history.size() > 1000000){
history.erase(history.begin());
#if __STATISTICS
++history_missed;
}
}else
++status_reduced;
#else
}
}
#endif
}
bool processLift_2(CLift & lift,__Policy & status,const std::vector<int> & dest,int capa,__History & history)
{
lift.Move();
const bool empty = lift.Empty(); //电梯是否一直是空的
lift.Unload(dest);
if(lift.Finish()){
AddStatus_2(lift,status,history);
return true;
}
if(lift.CanLoad()){ //有人可上电梯
if(lift.Empty()){
lift.direct_ = lift.Load(dest);
AddStatus_2(lift,status,history);
}else{
AddStatus_2(lift,status,history);
const U8 d = lift.Load(dest);
AddStatus_2(lift,status,history);
if(lift.direct_ != d){
lift.direct_ = d;
AddStatus_2(lift,status,history);
}
}
}else{ //无人可上电梯
if(lift.Empty()){
if(empty){
AddStatus_2(lift,status,history);
}else{
if(lift.TestDir())
AddStatus_2(lift,status,history);
lift.direct_ ^= 1; //改变方向
if(lift.TestDir())
AddStatus_2(lift,status,history);
}
}else
AddStatus_2(lift,status,history);
}
return false;
}
bool enumStatus_2(__Policy & status,const std::vector<int> & dest,int capa,__History & history)
{
__Policy tmp;
status.swap(tmp);
const size_t tmp_sz = tmp.size();
status.reserve(tmp_sz * 3);
for(size_t i = 0;i < tmp.size();++i)
if(processLift_2(tmp[i],status,dest,capa,history))
return true;
#if __STATISTICS
size_t sz = status.size();
if(int(sz) > status_max)
status_max = status.size();
double rate = sz;
rate /= tmp_sz;
if(rate > increase_rate)
increase_rate = rate;
#endif
return false;
}
int policy_2(const std::vector<int> & dest,int capa)
{
__Policy status(1);
memset(&status[0],0,sizeof status[0]);
status[0].direct_ = 1;
for(int i = 0;i < LEVEL;++i){
assert(0 <= dest[i] && dest[i] < LEVEL);
if(i == dest[i])
status[0].finished_ += S32(1) << i;
}
if(status[0].Finish())
return 0;
if(!(status[0].finished_ & 1))
status[0].load_ = 1;
printStatus(status);
__History history;
status.reserve(1000);
while(!enumStatus_2(status,dest,capa,history))
printStatus(status);
#if __STATISTICS
cout<<"history = "<<history.size()<<endl;
#endif
return status.back().ret_;
}
//------------------------------------------------------------
//--------------测试代码,保证算法的正确性--------------------
//batch test
void batch_test()
{
std::vector<int> dest(LEVEL);
for(int i = 0;i < LEVEL;++i){
for(int j = 0;j < LEVEL;++j){
dest[i] = j;
int actual = policy_1(dest,CAPA);
int test = policy_2(dest,CAPA);
if(actual != test){
cout<<"("<<LEVEL<<")";
for(int k = 0;k < LEVEL;++k)
cout<<dest[k]<<",";
cout<<"\nactual = "<<actual<<", test = "<<test<<endl;
}
}
}
#if __STATISTICS
PrintStats();
#endif
}
//------------------------------------------------------------
int main()
{
#if __TEST
batch_test();
#else //__TEST
srand((unsigned int)time(0));
//设置目的地
std::vector<int> dest;
destination(LEVEL,dest);
//计算必须走的距离
int minimal = minimalDistance(dest);
double start = clock();
//电梯实际的运行距离
int actual = policy_2(dest,CAPA);
# if __STATISTICS
PrintStats();
# endif
//计算算法效率
double rate = actual * CAPA * 1. / minimal;
start = clock() - start;
# ifndef WIN32
start /= 1000;
# endif
//输出结果
# if __SAMPLE == 1
cout<<minimal<<"\t"
<<actual<<"\t"
<<rate<<"\t"
<<start<<"\t"
<<endl;
# else //__SAMPLE
cout<<"minimal = "<<minimal<<endl
<<"actual = "<<actual<<endl
<<"CAPA = "<<CAPA<<endl
<<"rate = "<<rate<<endl
<<"Time : "<<start<<" ms\n";
# endif //__SAMPLE
#endif //__TEST
}