https://vjudge.net/problem/CodeForces-915D
D. Almost Acyclic Graph
Description
You are given a directed graph consisting of n vertices and m edges (each edge is directed, so it can be traversed in only one direction). You are allowed to remove at most one edge from it.
Can you make this graph acyclic by removing at most one edge from it? A directed graph is called acyclic iff it doesn't contain any cycle (a non-empty path that starts and ends in the same vertex).
Input
The first line contains two integers n and m (2 ≤ n ≤ 500, 1 ≤ m ≤ min(n(n - 1), 100000)) — the number of vertices and the number of edges, respectively.
Then m lines follow. Each line contains two integers u and v denoting a directed edge going from vertex u to vertex v (1 ≤ u, v ≤ n, u ≠ v). Each ordered pair (u, v) is listed at most once (there is at most one directed edge from u to v).
Output
If it is possible to make this graph acyclic by removing at most one edge, print YES. Otherwise, print NO.
Examples
input
3 4
1 2
2 3
3 2
3 1
output
YES
input
5 6
1 2
2 3
3 2
3 1
2 1
4 5
output
NO
Note
In the first example you can remove edge , and the graph becomes acyclic.
In the second example you have to remove at least two edges (for example, and ) in order to make the graph acyclic.
思路
题目大意:给定一个有向图,若至多删去一条边,仍未无环图,则输出“YES”;反之,若有环,则输出“NO”
题目思路:若至多删去一条边,分两种情况:(1)删去0条边,此时判断一下;(2)删去一条边,再判断。
如何删去一条边是本题关键。我们可以枚举删去的边,也就是枚举每个顶点,让其入度-1(删去指向到该点的一条边),
此时再toposort()进行判断。
注意:本题toposort()中需要删去一行代码:G【u】.clear().,不然结果错误。
AC Code
#include <iostream>
#include <cstring>
#include <cstdio>
#include <vector>
#include <queue>
#include <algorithm>
using namespace std;
const int nmax=505;
int inDegree[nmax];//存每个节点的入度
int ruDegree[nmax];//存每个节点的入度
vector<int>G[nmax];//邻接表
int n,m;//点数,边数
bool toposort(){
int num=0;//加到拓扑序列的顶点数
queue<int>q;
while(!q.empty()) q.pop();//清空队列
for(int i=1;i<=n;i++){//顶点编号:1~N
if(inDegree[i]==0){
q.push(i);//把入度为0的顶点扔进队列
}
}
while(!q.empty()){
int u=q.front();
q.pop();//删除该点
num++;
for(int i=0;i<G[u].size();i++){//遍历与点u相邻的所有边,删除之。
int v=G[u][i];
inDegree[v]--;
if(inDegree[v]==0){
q.push(v);
}
}
//G[u].clear(); //加这一行就错了
}
//printf("%d\n",num);
if(num==n) return true;
else return false;//有环路
}
int main(int argc, char** argv) {
while(~scanf("%d %d",&n,&m)){
for(int i=1;i<=n;i++){//初始化清空邻接表
G[i].clear();
}
memset(inDegree,0,sizeof(inDegree));
memset(ruDegree,0,sizeof(ruDegree));
int u,v;
for(int i=0;i<m;i++){
scanf("%d %d",&u,&v);
G[u].push_back(v);
inDegree[v]++;
ruDegree[v]++;
}
int flag;
if(toposort()){//不用删边,就是DAG了
puts("YES");
continue;
}
else{//有环,删除一条边再判断
flag=0;
for(int i=1;i<=n;i++){
memcpy(inDegree,ruDegree,sizeof(ruDegree));
if(inDegree[i]>=1){
inDegree[i]--;//删除一条边<=>该顶点的入度--;
if(toposort()){
flag=1;
puts("YES\n");
break;
}
}
}
}
if(flag==0){
puts("NO\n");
}
}
return 0;
}