最巧妙的方法是把两只蚂蚁相遇之后看出互相“穿透”。下面是老老实实的计算方法,呵呵。

 /**//*
* 题目:有一根27厘米的细木杆,在第3厘米、7厘米、11厘米、17厘米、23厘米这五个位置上各有一只蚂蚁。
* 木杆很细,不能同时通过一只蚂蚁。开始时,蚂蚁的头朝左还是朝右是任意的
* 它们只会朝前走或调头,但不会后退。
* 当任意两只蚂蚁碰头时,两只蚂蚁会同时调头朝反方向走。假设蚂蚁们每秒钟可以走一厘米的距离。
* 编写程序,求所有蚂蚁都离开木杆的最小时间和最大时间。
*/

 /**//*
* 1 2
* 0123456789012345678901234567
* + + + + +
* ---+---+---+-----+-----+----
*
* 从左至右构成链表,从左端开始检查相邻蚂蚁是否相遇,是否需要移动(相距1cm时无需移动,仅改变方向)
* 到达两端后从链表中删除
*
*/

#include <stdio.h>
#include <stdlib.h>

#define ALL 1

#if ALL
#define DETAIL 0
#else
#define DETAIL 1
#endif

#define ANT_NUM 5
#define LENGTH 27

#define LEFT -1
#define RIGHT 1

 typedef struct ant_struct {
struct ant_struct * left; // nearly ant on the left
struct ant_struct * right; // nearly ant on the right
int index;
int pos; // current position, from 0 to n
int dir; // which direction, left or right
int time; // elapsed time
} ant;

void print_state( ant* s )
  {
ant* p;

p = s->right;
 while ( p ) {
printf("(%d) postion: %2d direction: %s\n", p->index, p->pos,
(p->dir==LEFT)?"left":((p->dir==RIGHT)?"right":"Bad direction"));
p = p->right;
}
}

void set_direction( ant* head, int dir )
  {
ant* p = head->right;

 while ( p ) {
if ( dir % 2 )
p->dir = RIGHT;
else
p->dir = LEFT;
dir >>= 1;
p = p->right;
}
}

ant* init_state( int* pos, int dir, int ant_num )
  {
ant* head;
ant* p;
ant* q;
if ( (head = (ant *)malloc( sizeof(ant))) == NULL )
exit(1);

head->pos = 0;
head->dir = 0;
head->left = NULL;
head->right = NULL;

q = head;

 for ( int i = 0; i < ant_num; i++ ) {
if ( (p = (ant *)malloc( sizeof(ant))) == NULL )
exit(1);

p->index = i + 1;
p->pos = pos[i];
p->time = 0;

p->left = q;
q->right = p;
p->right = NULL;

q = q->right;
}
set_direction( head, dir );

return head;
}

void turn_round( ant* p )
  {
p->dir = -(p->dir);
}

bool ismoved( ant* a, ant* b)
  {
if ( a == NULL )
exit(1);
 if ( b == NULL ) {
return false;
}

 /**//*
* if there are 1 CM between a and b, they will meet and turn round
* and return to the initial position in the 1 second.
* if there are 0, they have meet and turn round now.
* otherwise they will go along their direction
*/
 if ( a->dir == RIGHT && b->dir == LEFT ) {
 /**//* meet and change its direction */
 if ( b->pos - a->pos == 1 ) {
turn_round( a );
turn_round( b );

return true;
}
 else if( b->pos - a->pos == 0 ) {
turn_round( a );
turn_round( b );

return false;
}
}

return false;
}

void moveall( ant* head )
  {
ant* p = head->right;

 while ( p ) {
 if ( ismoved( p, p->right ) == false ) {
 /**//* move towards its direction */
p->pos += p->dir;
p->time++;

 /**//* check whether it has gone out */
 if ( p->pos == 0 || p->pos == LENGTH ) {
 /**//* delete the ant */
#if DETAIL
printf("(%d) ant goes out at %d\n", p->index, p->time);
#endif
 /**//*
* if p is not at the end of list, the right node
* point to the left node.
* */
 if ( p->right ) {
 /**//* remove the ant at the begin of list */
p->right->left = p->left;
p->left->right = p->right;
free( p );
p = head;
}
 else {
 /**//* reach the end of list, remove the ant */
p->left->right = p->right;
free( p );
break;
}
}
}

 /**//* check next ant */
p = p->right;
}
}

 /**//* one possibility */
int process( int* pos, int dir, int ant_num )
  {
ant* s;
int time = 1;

s = init_state( pos, dir, ant_num );

 /**//* keep moving util no ants */
 while ( s->right ) {
 /**//* move all ants in a second */
moveall( s );
#if DETAIL
printf("\ntime:%d\n", time);
print_state( s );
#endif
time++;
}

printf("total time:%d\n", time);

return time;
}

int main( void )
  {
 int pos[ANT_NUM] = { 3, 7, 11, 17, 23 };
int ant_num = ANT_NUM;
int max = 0;
int min = 10000;
int now;
int possibility = (1<<ANT_NUM) - 1;

#if ALL
 while ( possibility >= 0 ) {

now = process( pos, possibility, ant_num );
if ( now < min ) min = now;
if ( now > max ) max = now;
printf("----possibility:%2d max:%2d min:%2d----\n\n", possibility, max, min);

possibility--;
}

printf("max time:%d, min time:%d\n", max, min);
#else
process( pos, 4, ant_num );
#endif

return 0;
}


|