[题解] [JSOI2013] 侦探jyy

题面

题解

看哪些事件不发生也对答案没有影响

假如说这件事不发生, 那么他的前驱都不会发生

然后把所有入度为零并且不是这件事的前驱的点全部设为发生, BFS 一遍, 看那 M 个是否都能发生

若能, 则该事件不一定发生

若不能, 该事件一定发生

复杂度 \(O(nm)\)

Code

#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdio>
#include <queue>
const int N = 100005; 
using namespace std;

int n, m, t, head[N], head1[N], cnt, tot, d[N], vis[N], hp[N], ck[N], ans[N];
struct edge { int to, nxt; } e[N], E[N]; 
queue<int> q; 

template < typename T >
inline T read()
{
    T x = 0, w = 1; char c = getchar();
    while(c < '0' || c > '9') { if(c == '-') w = -1; c = getchar(); }
    while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
    return x * w; 
}

inline void adde(int u, int v)
{
    e[++cnt] = (edge) { v, head[u] }, head[u] = cnt;
    E[++tot] = (edge) { u, head1[v] }, head1[v] = tot; 
}

bool check(int x)
{
    q.push(x), vis[x] = ++cnt;
    while(!q.empty())
    {
	int u = q.front(); q.pop();
	for(int v, i = head1[u]; i; i = E[i].nxt)
	    if(vis[v = E[i].to] != cnt) vis[v] = cnt, q.push(v); 
    }
    for(int i = 1; i <= t; i++)
	if(vis[hp[i]] == cnt) return 1;
    for(int i = 1; i <= n; i++)
	if(!d[i] && vis[i] != cnt) q.push(i), vis[i] = cnt;
    while(!q.empty())
    {
	int u = q.front(); q.pop();
	for(int v, i = head[u]; i; i = e[i].nxt)
	    if(vis[v = e[i].to] != cnt) vis[v] = cnt, q.push(v); 
    }
    for(int i = 1; i <= t; i++)
	if(vis[hp[i]] != cnt) return 1;
    return 0; 
}

int main()
{
    n = read <int> (), m = read <int> (), t = read <int> ();
    for(int u, v, i = 1; i <= m; i++)
    {
	u = read <int> (), v = read <int> ();
	adde(u, v), d[v]++; 
    }
    cnt = 0; 
    for(int i = 1; i <= t; i++)
	ck[hp[i] = read <int> ()] = 1;
    for(int i = 1; i <= n; i++)
	if(ck[i] || check(i)) ans[++ans[0]] = i;
    for(int i = 1; i <= ans[0]; i++)
	printf("%d%c", ans[i], i == ans[0] ? '\n' : ' '); 
    return 0; 
}
posted @ 2020-02-10 20:25  ztlztl  阅读(167)  评论(0)    收藏  举报