题目大意:给出N个点,M条有向边,每条有向边的长度为1,现在给出起点和终点,问这张图上有多少个点满足去掉该点后,使得起点到终点不连通(起点和终点也算)
解题思路:先求出最短路,因为长度都是1,所以最短路中的点肯定是最少的
去掉点,且使起点和终点不连通的点肯定是最短路上的点
把最短路上的点标记一下,然后从起点出发进行DFS,如果遇到标记过的点,就将起点重新赋值为走到的最远的标记的点,直到走到终点,dfs几次,就表示有多少个点是关键点,因为我们遇到了标记过的点就直接跳过,相当于不走该点
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
using namespace std;
const int MAXNODE = 100010;
const int MAXEDGE = 300010;
const int INF = 0x3f3f3f3f;
int S, T, tot, n, m;
int head[MAXNODE], tmp[MAXNODE], pre[MAXNODE], d[MAXNODE];
bool vis[MAXNODE], mark[MAXNODE];
struct Edge{
int v, next;
Edge() {}
Edge(int v, int next): v(v), next(next) {}
}E[MAXEDGE];
void AddEdge(int u, int v) {
E[tot] = Edge(v, head[u]);
head[u] = tot++;
}
void init() {
memset(head, -1, sizeof(head));
tot = 0;
int u, v;
for (int i = 0; i < m; i++) {
scanf("%d%d", &u, &v);
AddEdge(u, v);
}
scanf("%d%d", &S, &T);
}
bool BellmanFord() {
for (int i = 0; i < n; i++) {
d[i] = INF; vis[i] = false;
}
queue<int> Q;
d[S] = 0;
Q.push(S);
while (!Q.empty()) {
int u = Q.front(); Q.pop();
for (int i = head[u]; ~i; i = E[i].next) {
int v = E[i].v;
if (d[v] > d[u] + 1) {
d[v] = d[u] + 1;
pre[v] = u;
if (!vis[v]) {
vis[v] = true;
Q.push(v);
}
}
}
vis[u] = false;
}
if (d[T] == INF) return false;
int t = T;
memset(mark, 0, sizeof(mark));
while (t != S) {
mark[t] = true;
t = pre[t];
}
return true;
}
void dfs(int u) {
for (int i = head[u]; ~i; i = E[i].next) {
int v = E[i].v;
if (vis[v]) continue;
vis[v] = true;
if (mark[v]) {
if (d[v] > d[S]) S = v;
continue;
}
dfs(v);
}
}
int main() {
while (scanf("%d%d", &n, &m) != EOF) {
init();
if ( !BellmanFord()) printf("%d\n", n);
else {
memset(vis, 0, sizeof(vis));
int ans = 1;
while(S != T) {
dfs(S);
ans++;
}
printf("%d\n", ans);
}
}
return 0;
}