算法1
方法
bfs,枚举每个点,看这个点不发生是否可行,不可行则说明这个点必须发生,具体来说就是首先在逆图里,
这个点能到的所有点都不能发生了,包括这个点,如果这里面有D里的点,则这个点必须发生,同时,如果此时没有
矛盾,再让剩下所有点尽可能多的发生,如果不能覆盖D,则又矛盾
C++ 代码
#include<cstdio>
#include<algorithm>
#include<vector>
#include<cstring>
using namespace std;
const int N = 1010, M = 100010;
int h1[N], h2[N], e[M * 2], ne[M * 2], idx;
bool hp[N];
int q[N], hh, tt;
bool st[N];
bool inq[N];
int n, m, D;
struct Edge{
int a, b;
}edges[M];
int din[N];
void add(int h[], int a, int b)
{
e[idx] = b, ne[idx] = h[a], h[a] = idx ++;
}
bool check(int u)
{
if(hp[u]) return true;
hh = 0, tt = -1;
memset(st, 0, sizeof st);
q[++ tt ] = u;
st[u] = true;
while(hh <= tt)
{
int t = q[hh ++ ];
for(int i = h2[t]; ~i; i = ne[i])
{
int j = e[i];
if(hp[j]) return true;
if(!st[j])
{
st[j] = true;
q[ ++ tt ] = j;
}
}
}
hh = 0, tt = -1;
memset(inq, 0, sizeof inq);
for(int i = 1; i <= n; ++ i)
if(!st[i] && !din[i])
{
q[++ tt ] = i;
inq[i] = true;
}
while(hh <= tt)
{
int t = q[hh ++ ];
for(int i = h1[t]; ~i; i = ne[i])
{
int j = e[i];
if(!inq[j])
{
q[++ tt ] = j;
inq[j] = true;
}
}
}
for(int i = 1; i <= n; ++ i)
if(hp[i] && !inq[i])
return true;
return false;
}
int main()
{
scanf("%d %d %d", &n, &m, &D);
memset(h1, -1, sizeof h1);
memset(h2, -1, sizeof h2);
for(int i = 0; i < m; ++ i)
{
int a, b;
scanf("%d %d", &a, &b);
add(h1, a, b);
add(h2, b, a);
din[b] ++;
}
for(int i = 1; i <= D; ++ i)
{
int k;
scanf("%d", &k);
hp[k] = true;
}
for(int i = 1; i <= n; ++ i)
if(check(i))
printf("%d ", i);
return 0;
}