CodeForces 937D 936B Sleepy Game 有向图判环,拆点,DFS

题意:

  一种游戏,2个人轮流控制棋子在一块有向图上移动,每次移动一条边,不能移动的人为输,无限循环则为平局,棋子初始位置为$S$

  现在有一个人可以同时控制两个玩家,问是否能使得第一个人必胜,并输出一个解,否则判断是否能平局

题解:

  看到这个题首先我想到了强连通分量,但是事实证明求出强连通分量,缩点对解决问题没有什么帮助....

  能写一些看似正确的算法,但其实是假算法来的..

  

  ...........

  所以应该先分析策略,肯定是能赢就赢,不能赢就求平局,最后才算输

  平局很好判断,有向图上,从$S$点跑一边DFS,如果起点的可达子图包含环,就能平局了,具体方法类似tarjan

  其次是判断赢,简单来说就是棋子到达了一个点,路径长度为奇数(可以经过环),且这个点没有出边了

  换句话说,对于每一个点,其实有2种情况,第一个情况是你到达了这个点,到起点的距离是偶数,那肯定不会是终点了

                   第二个情况是你到达了这个点,到起点的距离是奇数,这时候如果还没有出边,那就是答案了,保存当前这个函数堆栈里的点即可

  可是,问题在于,你可以经过一个环,来使得距离变为奇数,没法简单的DFS

  我们考虑,到达每个点时有两种情况,那就是距离起点的距离奇/偶,因此考虑拆点

  把每个点拆开,分别代表奇点和偶点,每次加边的时候,把点一分为三

  $[1,n]$偶数点,$[n+1,2*n]$ 奇数点 $[2n+1,3n]$ 原图

  对于输入的边$(a,b)$,先保存原图,再连2条边,$(a,b+n),(a+n,b)$ 表示如果当前点是偶数距离,距离加一就会变成奇数,反之亦然

  意义在于,这个新的图包含了将"绕一个奇数长度的环,将偶数距离变成奇数距离"这种操作

  如果是奇数长度的环,在环路的尽头会连接到另外一个偶数距离,而偶数长度的环,则不连通

  然后就$O(2(m+n))$的DFS即可

  我试着把判环和找答案放在一个DFS里,但是不太好写,容易TLE,就分开了,判环用原图,找答案用拆点的图

  

#include <bits/stdc++.h>
#define IO ios::sync_with_stdio(false);cin.tie(0);cout.tie(0)
#define rep(ii,a,b) for(int ii=a;ii<=b;ii++)
using namespace std;
const int maxn=6e5+10;
const int maxm=1e6+10;
const int INF=0x3f3f3f3f;
int casn,n,m,k;
int head[maxn],nume;
struct node {int to,next;} e[maxm];
void add(int a,int b) {
	e[++nume]=(node) {b,head[a]};
	head[a]=nume;
}
int flag=0,draw=0;
int top,ans[maxn],s,vis[maxn];
void dfs(int now) {
	int cnt=0;
	vis[now]=1;
	ans[++top]=now;
	for(int i=head[now]; i; i=e[i].next) {
		int to=e[i].to;
		if(flag) return;
		if(!vis[to])dfs(to);
		cnt++;
	}
	if(now>n&&cnt==0)flag=1;
	if(flag==0)top--;
}
int dfs2(int now){
	if(vis[now]==2) return 1;
	vis[now]=2;
	for(int i=head[now];i;i=e[i].next){
		int to=e[i].to;
		if(!vis[to]){
			if(dfs2(to))return 1;
		}
		else if(vis[to]==2) return 1;
	}
	vis[now]=1;
	return 0;
}
int main() {
	IO;
	cin>>n>>m;
	rep(i,1,n) {
		int a,b;
		cin>>a;
		while(a--) {
			cin>>b;
			add(i+2*n,b+2*n);
			add(i,b+n);
			add(i+n,b);
		}
	}
	cin>>s;
	draw=dfs2(s+2*n);
	top=0;
	memset(vis,0,sizeof vis);
	dfs(s);
	if(flag) {
		cout<<"Win\n";
		for(int i=1; i<=top; i++) {
			cout<<(ans[i]>n? ans[i]-n:ans[i])<<‘ ‘;
		}
		cout<<endl;
	} else if(draw) cout<<"Draw\n";
	else cout<<"Lose\n";
	return 0;
}

  

原文地址:https://www.cnblogs.com/nervendnig/p/9236635.html

时间: 2024-08-28 05:35:56

CodeForces 937D 936B Sleepy Game 有向图判环,拆点,DFS的相关文章

CF 936B Sleepy Game(判环+BFS)

题目链接:http://codeforces.com/problemset/problem/936/B 题目: Petya and Vasya arranged a game. The game runs by the following rules. Players have a directed graph consisting of n vertices and medges. One of the vertices contains a chip. Initially the chip

HDU 5154 Harry and Magical Computer 有向图判环

题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=5154 题解: 有向图判环. 1.用dfs,正在访问的节点标记为-1,已经访问过的节点标记为1,没有访问过的节点标记为0,如果访问到-1的节点说明说有环. 1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<cmath> 5 using namespace std; 6 t

COJ 3012 LZJ的问题 (有向图判环)

传送门:http://oj.cnuschool.org.cn/oj/home/problem.htm?problemID=1042 试题描述: LZJ有一个问题想问问大家.他在写函数时有时候很头疼,如他写了这样几个函数: void f1(){   f2();   f3();}void f2(){   f3();}void f3(){   f1();}LZJ发现他无论怎么调换函数的位置,编译器总是不能通过编译,因为编译器规定调用的函数必须在当前函数之前写.还有一种情况是这样的:void f4(){

Almost Acyclic Graph CodeForces - 915D (思维+拓扑排序判环)

Almost Acyclic Graph CodeForces - 915D time limit per test 1 second memory limit per test 256 megabytes input standard input output standard output You are given a directed graph consisting of n vertices and m edges (each edge is directed, so it can

有向图判环

有这样一道编程面试题,给一个有向图的邻接矩阵,判别它是否有环. 题目麻烦在给的邻接矩阵是以 ‘字符输入流’ 的形式给出的,所以将其处理成数字形式的是首先要做的工作. 得到邻接矩阵之后,进行拓扑排序即可.假如能完成拓扑排序那就无环,如果不能,那就是有环. 样例输入: [[0, 1, 0], [0, 0, 1], [1, 0, 0]] [[0, 0, 0, 1, 0], [1, 0, 0, 0, 0], [0, 0, 0, 1, 1], [0, 0, 0, 0, 0], [0, 1, 0, 0, 0

有向图判环+拆解图求参会期望 SRM 660 Div1 Medium: Privateparty

题意:N个参加聚会,和一个数组a,ai表示第i个人讨厌的人,如果一个到聚会门口的时候发现他讨厌的人已经在聚会里面,则他不会参加聚会,否则他会参加聚会.ai==i表示他没有讨厌的人.N个人来的先后顺序是任意的,也就是说n个来的先后顺序构成的1到n的排列是任意的.问参加聚会的人的期望是多少? Privateparty Problem Statement Hero is inviting his friends to the party. He has n friends, numbered 0 th

Codeforces 937 D. Sleepy Game(DFS 判断环)

题目链接: Sleepy Game 题意: Petya and Vasya 在玩移动旗子的游戏, 谁不能移动就输了. Vasya在订移动计划的时候睡着了, 然后Petya 就想趁着Vasya睡着的时候同时定下策略, 如果可以赢得话输出Win 并输出路径, 如果步数在达到1e6的情况下,就认定为平局, 输出Draw,如果输的话就输出lost. 题解: 这题很容易就可以想到如果图中存在奇数长度的路径从起始点到叶子结点就是Win状态(这里还要注意绕环走的情况,比如说奇数长度的环是可以改变路径的奇偶性的

CodeForces 659E New Reform (图的遍历判环)

Description Berland has n cities connected by m bidirectional roads. No road connects a city to itself, and each pair of cities is connected by no more than one road. It isnot guaranteed that you can get from any city to any other one, using only the

SDNU 1089.拓扑排序(拓扑判环小顶堆)

Description 给定一个有向图,若图无环,则将其进行拓扑排序并输出,否则输出IMPOSABLE. Input 第一行为两个整数n(1<=n<=1000).m(1<=m<=100000): 之后m行,每行两个整数a.b(0 < a, b <= n)表示一条从a到b的有向边. Output 若存在环,输出IMPOSABLE,否则输出一行用一个空格隔开的拓扑排序的结果,若存在多个结果,输出字典序最小的. Sample Input 5 4 1 2 2 3 3 4 4 5