您的位置:首页 > 其它

UVa 243 - Theseus and the Minotaur (II)

2014-03-27 22:43 387 查看
题目:忒修斯和牛头人,这是个很有名的古希腊神话故事。题目的描述也不是一般的长啊。

估计很多人是被英文吓跑了,╮(╯▽╰)╭为了干掉他,看了3天的题目。

题目大概的意思:这有一个迷宫,由山洞和隧道组成,T(忒修斯)和M(牛头人)开始时

处于迷宫的隧道中,然后向前走。T的运动规则是,进入到一个洞穴后,就靠着右侧的强走,

就是走到他来的那个洞口的逆时针的下一个洞口处;如果这个隧道没走过,他就标记一下,

然后沿着它向前走,如果标记过,他就寻找逆时针顺序的下一个隧道口。M的运动规律相反,

他是靠左侧走的,也就是顺时针的选取隧道口,标记则跳过,没标记就标记,然后走进去。

如果,他们在同一个山洞相遇,那么T就杀死M;如果,他们在隧道相遇,那么M就杀死T。

如果T走进的山洞,发现M在他之前走过,那么他就会在这个山洞中点燃一根蜡烛;然后,

沿着M最后走过的隧道前进。如果M走进山洞时,发现有蜡烛,他就退回到上一个山洞。

求最后谁杀了谁(题目的数据满足,他们一定相遇)。

分析:模拟。数据利用双线链表储存,可双向读取。这种题目的难点就是划分子操作。

开始时,我尝试划分成两个子操作:

1.move_caverns_T(a,b),T从a山洞,移动到b山洞。

2.move_caverns_M(a,b),M从a山洞,移动到b山洞。

这样对于T,M都需要记录之前的节点和当前选择的隧道。

这样划分的问题就是:判断在隧道相遇有困难。所以想到下面的划分形式:

1.move_caverns_to_passage_T(a,b),T从a移动到ab间的隧道中。

2.move_caverns_to_passage_M(a,b),M从a移动到ab间的隧道中。

3.move_passage_to_caverns_T(a,b),T从ab间的隧道中移动到b。

4.move_passage_to_caverns_M(a,b),M从ab间的隧道中移动到b。

每次运行的顺序是:(a,b先后顺序无所谓,d,e的先后顺序无所谓)

a.move_passage_to_caverns_T(a,b)

b.move_passage_to_caverns_M(a,b)

c.判断M和T是不是在一个洞穴,是则M被杀

d.move_caverns_to_passage_T(a,b)

e.move_caverns_to_passage_M(a,b)

f.判断M和T是不是在同一个隧道中,是则T被杀
任何一种有解的数据,都可以用上面的序列求解,初始在隧道相遇除外(需要特判)。

#include <iostream>
#include <cstdlib>
#include <cstdio>

typedef struct dnode
{
	int    point;
	int    flag1;//标记T走过,取值0和1 
	int    flag2;//标记M走过,取值>0,表示访问顺序 
	dnode* left;
	dnode* right;
}dlink;
dlink  Node[2000];
dlink* Head[30];

int  d_size;

void dlink_inital( void )
{
	d_size = 0;
	for ( int i = 0 ; i < 26 ; ++ i )
		Head[i] = NULL;
}

void dlink_add( int a, int b )
{
	if ( !Head[a] ) {
		Node[d_size].left  = &Node[d_size];
		Node[d_size].right = &Node[d_size];
		Head[a] = &Node[d_size];
	}else {
		Node[d_size].right = Head[a];
		Node[d_size].left  = Head[a]->left;
		Head[a]->left->right = &Node[d_size];
		Head[a]->left = &Node[d_size];
	}
	Node[d_size].flag1 = 0;
	Node[d_size].flag2 = 0;
	Node[d_size].point = b;
	d_size ++;
}

//计算下一个隧道位置 
dlink* dlink_next( dlink* p, int id, int forword )
{
	dlink *t = Head[p->point]; 
	while ( t->point != id ) 
		t = t->right;
	return (forword?t->right:t->left);
}

//返回M最近走过的隧道 
dlink* dlink_last( dlink* p )
{
	dlink *t = p,*m = p,*q; 
	for ( q = t->right; t != q ; q=q->right )
		if ( m->flag2 < q->flag2 ) 
			m = q;
	return m;
}

//标记M到过(2),或者点燃蜡烛(1) 
int visit[30];

int main()
{
	char a,b,c,d;
	while ( ( a = getchar() ) != '#' ) {
		dlink_inital();
		while ( a != '@' ) {
			getchar();
			while ( ( b = getchar() ) != '\n' )
				dlink_add( a-'A', b-'A' );
			a = getchar();
		}
		a = getchar();b = getchar();
		c = getchar();d = getchar();
		    getchar();
		
		if ( ( a == c && b == d ) || ( a == d && b == c ) ) {
			printf("Theseus is killed between %c and %c\n",a,b);
			continue;
		}
		
		for ( int i = 0 ; i < 26 ; ++ i )
			visit[i] = 0;
		int T = a-'A',M = c-'A',S;
		dlink *p = Head[a-'A'];
		while ( p->point != b-'A' ) p = p->right;
		dlink *q = Head[c-'A'];
		while ( q->point != d-'A' ) q = q->right;
		int flagp = 1,flagq = 1,Mmark = 1;
		while ( 1 ) {
			//Minotaur into cavern
			S = M;
			M = q->point;
			q = dlink_next( q, S, 0 );
			if ( visit[M] == 1 ) {
				q = dlink_next( q->right, M, 0 );
				M = S;
			}else visit[M] = 2;
			//Thseus into cavern 
			S = T;
			T = p->point;
			p = dlink_next( p, S, 1 );
			
			if ( T == M ) {//meet in cavern
				printf("The Minotaur is slain in %c\n",M+'A');
				break;
			}
			
			//Thseus into passage
			if ( visit[T] == 2 ) {
				visit[T] = 1;
				p = dlink_last( p );
			}else while ( p->flag1 ) p = p->right;
			p->flag1 = 1;
			//Minotaur into passage	
			while ( q->flag2 ) q = q->left;
			q->flag2 = Mmark ++;
			
			if ( M == p->point && T == q->point ) {//meet in passage
				printf("Theseus is killed between %c and %c\n",'A'+T,'A'+M);
				break;
			}
		}
	}
	return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: