Tyvj p1371 蛇灵迷宫 (博弈 输出路径)

蛇灵迷宫

描述 Description

李元芳和闪灵在打斗中不慎掉入了蛇灵总坛地下的迷宫,十分恐惧~~~ 迷宫是由n个点组成的,他们停留在1号点,规定他们两个人在一起,每个人轮流决定下一步怎么走,并且只能从序号小的点走向序号大的点,最后无法决定接下来怎么走(走到死路)的人会被处死,另一个人得以逃生。

在这个危机的时刻,拿到地图的李元芳必须以迅雷不及掩耳盗铃的速度判断出自己能否通过做出正确决策来逃生(既然对方是闪灵嘛!当然他每次做出的决策肯定是最好的),所以李元芳向会OI的你求救~~~请你判断出元芳能否通过做出正确决策来逃生,并且求出在他和闪灵同时做出正确决策的情况下,他们两人可能到达的点的编号。

输入格式 InputFormat

第一行三个数 n,m,f

n表示迷宫的点数 m表示迷宫的边数 f表示第一次作出决定的人(0-闪灵先 1-元芳先)

接下来m行 每行两个数x和y 表示编号为x的点和和编号为y的点是连通的

数据范围:

1<=n<=1000 1<=m<=10000 0<=f<=1

1<=x,y<=n

输出格式 OutputFormat

第一行一个数l (1表示最后元芳能活下来,0表示闪灵能活下来)

第二行按从小到大顺序打出两人可能到达的点的编号,中间用空格隔开

样例输入 SampleInput

5 5 1

1 2

1 3

2 4

4 5

3 5

样例输出 SampleOutput 

7

思路:

比较坑爹的一个题,此题的难点在于可能路径点的输出,并且要注意的是,路径不止一条,要输出的是所有可行路径经过点的并集。。

方法,首先SG函数判断输赢,然后记忆化搜索确定路径点,方法如下

要说求赢家第一步的选择,大家可能不陌生,只要一个公式即可,这儿其实类似的道理。但要说的是赢家做出选择(不唯一)后,输家的选择是任意的(因为不管输家怎么选择,赢家还是会赢,选择的关键在赢家),下一次赢家继续以输家选择的点作为起点做选择,以次类推。

代码:

#include <stdio.h>
#include <string.h>
#define N 1005

bool map[N][N];			// 记录关系
bool end[N];			// 标记出度为0的点(终点)
int sg[N];
bool ans[N];			// 标记所有要走的点(答案)
int dp[N][2];			// 用于记忆化搜索,记录之后的路径是否能走(能为1,不能为0,-1代表还未走过),二维是因为要分先后手(先手走过,后手不一定)
int n, m, f;

int getSG(int k);		// 获取SG值

bool dfs(int start, int k)			// 深搜获得路径,start为当前点下标,k为输赢家标识,0表示输家,1表示赢家
{
	if(dp[start][k] != -1)			// 检查之后的结点是否已经走过了
		return dp[start][k] == 0 ? 0 : 1;

	int i;
	bool ls, ok = 0;
	if(k == 1){						// 赢家选择
		for(i = start + 1; i <= n; i ++){
			if(map[start][i] && sg[i] < (sg[i] ^ sg[start])){
				if(end[i] == 0){					// 赢家走到终点,记录路径,返回1
					ans[i] = 1;
					ok = 1;
				}
				ls = dfs(i, 0);						// ls == 1 表示此路径可走通,标记路径上的点
				if(ls){
					ok = 1;
					ans[i] = 1;
				}
			}
		}
	}
	else{							// 输家选择, 因为必输,所以在先手选择正确的基础上,所以它的选择是随意的(但注意,这儿先手的选择不一定是对的)
		for(i = start + 1; i <= n; i ++)			// 判断赢家选择是否正确,不正确直接返回0
			if(map[start][i] && sg[i] < (sg[i] ^ sg[start]))
				return 0;
		for(i = start + 1; i <= n; i ++){
			if(map[start][i]){
				if(sg[i] < (sg[i] ^ sg[start]))		// 输家走到终点,表示赢家有选择错误,停止搜索,返回0
					return 0;
				ls = dfs(i, 1);
				if(ls){								// ls == 1 表示此路径可走通,标记路径上的点
					ok = 1;
					ans[i] = 1;
				}
			}
		}
	}

	return dp[start][k] = ok;		// 记录当前状态
}

int main()
{
	int x, y, i;
	while(scanf("%d%d%d", &n, &m, &f) != EOF){
		memset(sg, -1, sizeof(sg));				// 初始化
		memset(map, 0, sizeof(map));
		memset(end, 0, sizeof(end));
		memset(ans, 0, sizeof(ans));
		memset(dp, -1, sizeof(dp));
		while(m --){
			scanf("%d%d", &x, &y);
			if(x == y)
				continue;
			if(x > y){
				int temp = x;
				x = y;
				y = temp;
			}
			map[x][y] = 1;
			end[x] = 1;							// 记录出度
		}

		for(i = 1; i <= n; i ++){
			if(end[i] == 0)						// 出度为0的点为必败点,sg值为0
				sg[i] = 0;
		}

		getSG(1);

		int win = (sg[1] != 0) ? f : (f + 1) % 2;
		printf("%d\n", win);					// 输出赢家

		ans[1] = 1;
		dfs(1, sg[1] == 0 ? 0 : 1);

		for(i = 1; i <= n; i ++){				// 输出路径,注意空格处理
			if(ans[i]){
				printf("%d", i);
				break;
			}
		}
		for(i = i + 1; i <= n; i ++){
			if(ans[i])
				printf(" %d", i);
		}
		printf("\n");
	}

	return 0;
}

int getSG(int k)				// 获取SG值
{
	if(sg[k] != -1)
		return sg[k];

	bool hash[N];
	memset(hash, 0, sizeof(hash));
	for(int i = k + 1; i <= n; i ++){
		if(!map[k][i])
			continue;
		sg[i] = getSG(i);
		hash[sg[i]] = 1;
	}
	for(int j = 0; ; j ++)
		if(!hash[j])
			return sg[k] = j;
}

Tyvj p1371 蛇灵迷宫 (博弈 输出路径)

时间: 2024-10-12 21:59:53

Tyvj p1371 蛇灵迷宫 (博弈 输出路径)的相关文章

poj(3984)——迷宫问题(输出路径)

题目的大致意思是:给你一个5*5的迷宫,然后你只能往上,下,左,右四个方向走,然后0代表的是可以走的路,1代表的是墙不可以走.然后让我们求出从左上角到右下角的最短路线及其长度. 求长度是好做的,但是输出路径这个我还是第一次碰到. 这里我们使用的队列不可以是STL中的queue了,要用数组来写,因为我们在这里需要头尾两个指针. 然后我们这里还要用到一个保存前驱节点的数组pre,这样在我们输出路径的时候就可以回溯上去. #include<stdio.h> #include<string.h&

迷宫问题---poj3984(bfs,输出路径问题)

题目链接 主要就是输出路径问题: pre[x][y]表示到达(x,y)是由点(pre[x][y].x,  pre[x][y].y)而来: #include<stdio.h> #include<iostream> #include<string.h> #include<queue> #include<algorithm> using namespace std; #define N 220 #define INF 0xfffffff int dir

蚁群算法求解迷宫最优路径问题

本段程序的基本思想是利用蚁群算法中的蚁周模型,来对全局的迷宫图进行信息素的跟新 和为每一只蚂蚁选择下一个方格. 一共会进行RcMax = 2000轮模拟(理论上模拟的次数越多结果 会越接近真实值),而在每一轮中会排除 M = 10只蚂蚁进行探路.同时在算法的回溯思想上采用的 是栈的数据结构来实现的.当栈最终为空时则表示无解.但同时这段程序的一缺点就是:由于我没在 算法中对每一轮的每只探路蚂蚁采用多线程的模式,所以整体的运行效率还不是很高.如读者有好的 思想或建议,请留言. #include<io

hdu 1026 Ignatius and the Princess I(bfs搜索+输出路径)

题目来源:hdu-1026 Ignatius and the Princess I Ignatius and the Princess I Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 14677 Accepted Submission(s): 4653 Special Judge Problem Description The Princ

POJ 3984 迷宫问题 (路径记录)

K - 迷宫问题 Crawling in process... Crawling failed Time Limit:1000MS     Memory Limit:65536KB     64bit IO Format:%I64d & %I64u Submit Status Description 定义一个二维数组: int maze[5][5] = { 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 1

MapReduce 编程 系列八 根据输入路径产生输出路径和清除HDFS目录

有了前面的MultipleOutputs的使用经验,就可以将HDFS输入目录的路径解析出来,组成输出路径,这在业务上是十分常用的.这样其实是没有多文件名输出,仅仅是调用了MultipleOutputs的addNamedOutput方法一次,设置文件名为result. 同时为了保证计算的可重入性,每次都需要将已经存在的输出目录删除. 先看pom.xml, 现在参数只有一个输入目录了,输出目录会在该路径后面自动加上/output. <project xmlns="http://maven.ap

vc下DLL项目设置dll和lib库输出路径以及使用lib/dll库时的包含路径

include 头文件包含路径设置: project->setting->C/C++->常规: Additional include directories(附加包含目录): ../../include等等 链接文件输出目录:    project->setting->配置属性->常规:输出目录 例如:输出目录:$(SolutionDir)Temp\Link\$(ProjectName)\$(ConfigurationName) 解释:项目目录-Temp-Link-工程

HD1385Minimum Transport Cost(Floyd + 输出路径)

Minimum Transport Cost Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Submission(s): 9109    Accepted Submission(s): 2405 Problem Description These are N cities in Spring country. Between each pair of cities

poj3436 ACM Computer Factory, 最大流,输出路径

POJ 3436 ACM Computer Factory 电脑公司生产电脑有N个机器,每个机器单位时间产量为Qi. 电脑由P个部件组成,每个机器工作时只能把有某些部件的半成品电脑(或什么都没有的空电脑)变成有另一些部件的半成品电脑或完整电脑(也可能移除某些部件).求电脑公司的单位时间最大产量,以及哪些机器有协作关系,即一台机器把它的产品交给哪些机器加工. Sample input 3 4 15  0 0 0  0 1 0 10  0 0 0  0 1 1 30  0 1 2  1 1 1 3