Codeforces Round #731 (Div. 3) G. How Many Paths? dfs + 拓扑 + 思维

传送门

题意:

给你一张 n n n个点 m m m条边的图,让你对每个点确定一个编号,规则如下:

( 1 ) (1) (1) 对于不能到的点编号为 0 0 0

( 2 ) (2) (2) 对于只有一条路径能到这个点的点编号为 1 1 1

( 3 ) (3) (3) 对于有不止一条路径能到这个点的点编号为 2 2 2

( 4 ) (4) (4) 对于有无数条路径能到这个点的点编号为 3 3 3

思路:

考虑一次 d f s dfs dfs能得到什么东西,我们可以通过一次 d f s dfs dfs确定下来不能到达的点,还可以确定只有一条路径的点,但是不能确定所有不止一条路径的点,因为有可能到某个点路径有若干条,这个点能到的点应该也可以有两条路径到达,但是如果只跑一次是确定不下来的,所以我们给这些点打个标记,让后再跑一次 d f s dfs dfs,这样就可以确定下来所有 0 , 1 , 2 0,1,2 0,1,2的点了。

考虑 − 1 -1 1的点怎么确定,看到环应该可以想到拓扑排序,所以我们把 1 1 1号点仍队列里面,让后跑拓扑,不能到的点就是 − 1 -1 1点,因为有环的话会类似一个瓶颈卡住他下面的点以及环上的点,所以不能到的点即为可以经过环到达的点,直接标记为 − 1 -1 1即可。

但是这个题细节很多很多,比如如果一开始 1 1 1就在环里,我们这个时候全部赋值为 − 1 -1 1即可,需要特判一下。还有需要将不能经过的点能到达的点的度数减去,因为如果不去掉,拓扑排序这些点就会被认为是环能经过的点,是不合理的。

// Problem: G. How Many Paths?
// Contest: Codeforces - Codeforces Round #731 (Div. 3)
// URL: https://codeforces.com/contest/1547/problem/G
// Memory Limit: 512 MB
// Time Limit: 4000 ms
// 
// Powered by CP Editor (https://cpeditor.org)

//#pragma GCC optimize("Ofast,no-stack-protector,unroll-loops,fast-math")
//#pragma GCC target("sse,sse2,sse3,ssse3,sse4.1,sse4.2,avx,avx2,popcnt,tune=native")
//#pragma GCC optimize(2)
#include<cstdio>
#include<iostream>
#include<string>
#include<cstring>
#include<map>
#include<cmath>
#include<cctype>
#include<vector>
#include<set>
#include<queue>
#include<algorithm>
#include<sstream>
#include<ctime>
#include<cstdlib>
#include<random>
#include<cassert>
#define X first
#define Y second
#define L (u<<1)
#define R (u<<1|1)
#define pb push_back
#define mk make_pair
#define Mid ((tr[u].l+tr[u].r)>>1)
#define Len(u) (tr[u].r-tr[u].l+1)
#define random(a,b) ((a)+rand()%((b)-(a)+1))
#define db puts("---")
using namespace std;

//void rd_cre() { freopen("d://dp//data.txt","w",stdout); srand(time(NULL)); }
//void rd_ac() { freopen("d://dp//data.txt","r",stdin); freopen("d://dp//AC.txt","w",stdout); }
//void rd_wa() { freopen("d://dp//data.txt","r",stdin); freopen("d://dp//WA.txt","w",stdout); }

typedef long long LL;
typedef unsigned long long ULL;
typedef pair<int,int> PII;

const int N=1000010,mod=1e9+7,INF=0x3f3f3f3f;
const double eps=1e-6;

int n,m;
vector<int>v[N];
int id[N],st[N],d[N];

void dfs1(int u) {
	id[u]=1; st[u]=1;
	for(auto x:v[u]) {
		if(st[x]) {
			id[x]=2;
			continue;
		}
		dfs1(x);
	}
}

void dfs2(int u,int now) {
	st[u]=1;
	if(id[u]==2) now=2;
	id[u]=now;
	for(auto x:v[u]) {
		if(st[x]) continue;
		dfs2(x,now);
	}
}

void topsort() {
	if(id[1]==2) {
		for(int i=1;i<=n;i++) if(id[i]) id[i]=-1;
		return;
	}
	queue<int>q;
	for(int i=1;i<=n;i++) st[i]=0;
	q.push(1);
	while(q.size()) {
		int u=q.front(); q.pop();
		st[u]=1;
		for(auto x:v[u]) {
			if(--d[x]==0) q.push(x);
		}
	}
	for(int i=1;i<=n;i++) if(!st[i]&&id[i]) id[i]=-1;
}

int main()
{
//	ios::sync_with_stdio(false);
//	cin.tie(0);
	
	int _; scanf("%d",&_);
	while(_--) {
		scanf("%d%d",&n,&m);
		for(int i=1;i<=n;i++) id[i]=st[i]=d[i]=0,v[i].clear();
		for(int i=1;i<=m;i++) {
			int a,b; scanf("%d%d",&a,&b);
			d[b]++; v[a].pb(b);
		}
		dfs1(1);
		for(int i=1;i<=n;i++) if(!st[i]) {
			for(auto x:v[i]) d[x]--;
		}
		for(int i=1;i<=n;i++) st[i]=0;
		dfs2(1,1);
		topsort();
		for(int i=1;i<=n;i++) printf("%d ",id[i]);
		puts("");
	}



	return 0;
}
/*

*/









评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值