2024/2/15
补题
codeforce925 F F - Chat Screenshots
题意:
给定一个队列,n个人,每个人的视角是把自己放在最前面,剩下按照原来顺序。现在给你m个视角,问你是否合法。
思路:
我们可以先假设每个队列都是合法的,然后找到矛盾就行了。
但是每个人都会把自己放在最前面,所以我们不用管第一个。剩下的记录前后位置,用有向图存储。矛盾就是有向图出现回路。
问题1:怎么得到有向图?
有向图之前我习惯用vector的邻接矩阵,但是这个题会有重复的点记录,所以用set[]更好。
问题2:怎么判断有向图是否有回路?
有两种办法:
(1)拓扑排序,两个步骤,入度为零的点压入队列,把队列中的点邻边删除,重复这两个步骤,还有剩余的点就是环
(2)dfs和bfs,这两个是搜索,需要一个状态数组,状态数组需要记录三个状态(搜索完,正在搜索,没有搜索),如果两个正在搜索的点相遇,那就是出现环。
拓扑
#include <bits/stdc++.h>
using namespace std;
#define int long long
set<int> adj[200005];
int in[200005] = {0};
void solve() {
int n, m;
cin >> n >> m;
for (int i = 1; i <= n; i++) {
adj[i].clear();
in[i] = 0;
}
for (int i = 0; i < m; i++) {
int la, t;
cin >> la;
for (int i = 0; i < n - 1; i++) {
cin >> t;
if(i && adj[la].find(t) == adj[la].end() ) {
adj[la].insert(t);
in[t]++;
}
la = t;
}
}
queue<int>q;
int cnt = 0;
for (int i = 1; i <= n; i++) {
if(in[i] == 0) {
q.push(i);
cnt++;
}
}
while(q.size()) {
int x = q.front();
q.pop();
for (auto it : adj[x]) {
if(--in[it] == 0) {
q.push(it);
cnt++;
}
}
}
if(cnt == n) {
cout << "YES\n";
}
else {
cout << "NO\n";
}
}
signed main() {
ios::sync_with_stdio(0);
cin.tie(0), cout.tie(0);
int T = 1;
cin >> T;
while(T--) {
solve();
}
return 0;
}
dfs
#include <bits/stdc++.h>
using namespace std;
#define int long long
set<int> adj[200005];
int state[200005];
bool ok = 1;
//0-no 1-ing 2-ok
bool dfs(int x) {
for (auto it : adj[x]) {
if(state[it] == 0) {
state[it] = 1;
if(!dfs(it)) {
return 0;
}
state[it] = 2;
}
else if(state[it] == 1) {
ok = 0;
return 0;
}
}
return 1;
}
void solve() {
int n, m;
cin >> n >> m;
for (int i = 1; i <= n; i++) {
adj[i].clear();
state[i] = 0;
}
for (int i = 0; i < m; i++) {
int la, t;
cin >> la;
for (int i = 0; i < n - 1; i++) {
cin >> t;
if(i && adj[la].find(t) == adj[la].end() ) {
adj[la].insert(t);
}
la = t;
}
}
ok = 1;
for (int i = 1; ok && i <= n; i++) {
if(!state[i]) {
dfs(i);
}
}
if(ok) {
cout << "YES\n";
}
else {
cout << "NO\n";
}
}
signed main() {
ios::sync_with_stdio(0);
cin.tie(0), cout.tie(0);
int T = 1;
cin >> T;
while(T--) {
solve();
}
return 0;
}