原文链接:https://www.cnblogs.com/Time25/p/19969092.html
https://atcoder.jp/contests/abc456/tasks/abc456_e

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define endl '\n'
#define ep emplace
#define pb push_back
#define all(a) a.begin(),a.end()
#define mod 998244353
#define MOD 1000000007
#define N 200010
//分层图+反向拓扑
void solve(){
int n,m;cin>>n>>m;
vector<vector<int>>g(n+1);
vector<string>s(n+1);
while(m--){
int x,y;cin>>x>>y;
g[x].push_back(y);
g[y].push_back(x);
}//建立边
int w;cin>>w;
vector<vector<int>>f(n+1,vector<int>(w));
vector<vector<int>>h(n+1,vector<int>(w));
//h[i][j]:时刻j位于节点i的时候,下一秒有多少个合法的移动选项,包括呆在原地和去可以去到的邻居
for(int i=1;i<=n;i++){
cin>>s[i];
for(int j=0;j<w;j++){
if(s[i][j]=='x')f[i][j]=1;
}
}//死掉的节点,已经是X的了
for(int i=1;i<=n;i++){
for(int j=0;j<w;j++){
if(!f[i][j]){
int prej=(j-1+w)%w;
h[i][prej]++;
for(int v:g[i]){
h[v][prej]++;
}
}
}
}//算出各个点下一步可以走的路数
queue<pair<int,int>>q;
for(int i=1;i<=n;++i){
for(int j=0;j<w;++j){
if(!f[i][j]&&h[i][j]==0){
f[i][j]=1;q.push({i,j});
}
}
}//把那些死胡同的点,也就是是o,但是下一步一个o也走不到的点push到队列里
while(!q.empty()){
int u=q.front().first;//城市
int t=q.front().second;//时间
int pret=(q.front().second-1+w)%w;
q.pop();
if(!f[u][pret]&&--h[u][pret]==0){
f[u][pret]=1;
q.push({u,pret});
}
for(int v:g[u]){
if(!f[v][pret]&&--h[v][pret]==0){
f[v][pret]=1;
q.push({v,pret});
}
}
}//类似反向拓扑
bool flag=false;
for(int i=1;i<=n;i++)if(f[i][0]==0)flag=true;
//如果在0时刻有以某个f[i][0]是0,说明从这个点出发有一条成环的每一天都可以是放假的路线
//为什么是这样呢:因为如果这条路不是有环的而是有尽头的,那么这个尽头就会呗标记为1,然后从后往前所有的都会被标记为1
//就没有会被标记为0的
if(flag)cout<<"Yes"<<endl;
else cout<<"No"<<endl;
}
signed main(){
ios::sync_with_stdio(0);
cin.tie(0);cout.tie(0);
int t;cin>>t;
while(t--)solve();
return 0;
}
// TRAINING LOG · 第 61 / 76 篇训练记录 · 成文于 2026.05.03 · 下午 16:33