F. Simple Cycles Edges
time limit per test
2 seconds
memory limit per test
256 megabytes
input
standard input
output
standard output
You are given an undirected graph, consisting of nn vertices and mm edges. The graph does not necessarily connected. Guaranteed, that the graph does not contain multiple edges (more than one edges between a pair of vertices) or loops (edges from a vertex to itself).
A cycle in a graph is called a simple, if it contains each own vertex exactly once. So simple cycle doesn't allow to visit a vertex more than once in a cycle.
Determine the edges, which belong to exactly on one simple cycle.
Input
The first line contain two integers nn and mm (1≤n≤100000(1≤n≤100000, 0≤m≤min(n⋅(n−1)/2,100000))0≤m≤min(n⋅(n−1)/2,100000)) — the number of vertices and the number of edges.
Each of the following mm lines contain two integers uu and vv (1≤u,v≤n1≤u,v≤n, u≠vu≠v) — the description of the edges.
Output
In the first line print the number of edges, which belong to exactly one simple cycle.
In the second line print the indices of edges, which belong to exactly one simple cycle, in increasing order. The edges are numbered from one in the same order as they are given in the input.
Examples
input
Copy
3 3 1 2 2 3 3 1
output
Copy
3 1 2 3
input
Copy
6 7 2 3 3 4 4 2 1 2 1 5 5 6 6 1
output
Copy
6 1 2 3 5 6 7
input
Copy
5 6 1 2 2 3 2 4 4 3 2 5 5 3
output
Copy
0
给出一个无向图,求出所有的只在一个简单环中出现的边。简单环:环上点两两不同。
找出所有的点双联通分量,看其点的个数和边的个数是否一样,若是,则累加上边的个数,并记录边。
do{
x = stk.top();
stk.pop();
tmp_edge_set.insert(edge[x].id);
tmp_ver_set.insert(edge[x].to);
//在这里存储一个点双联通分量里的边、点
}while(x!=i);
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<stack>
#include<vector>
#include<set>
using namespace std;
const int maxn = 1e5+7;
struct EDGE{
int to,next,id;
}edge[maxn*2];
int n,m,head[maxn],edge_num,Inx,dfn[maxn],low[maxn],used[maxn*2];
stack<int> stk;
vector<int> ans;
void add_edge(int u,int v,int id){
edge[edge_num].to = v;
edge[edge_num].next = head[u];
edge[edge_num].id = id;
head[u] = edge_num++;
}
void tarjan(int u,int fa){
dfn[u] = low[u] = ++Inx;
for(int i=head[u];i!=-1;i=edge[i].next){
int v = edge[i].to;
if(v==fa) continue;
if(used[i]) continue;
used[i] = used[i^1] = 1;
stk.push(i);
if(!dfn[v]){
tarjan(v,u);
low[u] = min(low[u],low[v]);
if(dfn[u]<=low[v]){
set<int> tmp_ver_set;//记录点的数量
set<int> tmp_edge_set;//记录边的数量
tmp_ver_set.insert(u);
int x;
do{
x = stk.top();
stk.pop();
tmp_edge_set.insert(edge[x].id);
tmp_ver_set.insert(edge[x].to);
//在这里存储一个点双联通分量里的边、点
}while(x!=i);
if(tmp_edge_set.size()==tmp_ver_set.size())
for(set<int>::iterator it=tmp_edge_set.begin();it!=tmp_edge_set.end();it++)
ans.push_back(*it);//把边加进去
}
}
else low[u] = min(low[u],dfn[v]);
}
}
int main(){
scanf("%d %d",&n,&m);
memset(head,255,sizeof(head));
for(int i=1;i<=m;i++){
int u,v;
scanf("%d %d",&u,&v);
add_edge(u,v,i);
add_edge(v,u,i);
}
for(int i=1;i<=n;i++) if(!dfn[i]) tarjan(i,i);
sort(ans.begin(),ans.end());
printf("%d\n",ans.size());
for(int i=0;i<(int)ans.size();i++) printf("%d ",ans[i]);
return 0;
}