模型就是在一个双连通分量重找桥。
注意几点:
1.重边的处理 。
每一条无向边建成两条有向边。每条边有一个编号,编号从0开始。即第一条无向边记为两条有向边后编号为0,1.第二条边编号为2,3。所以对于任意一条编号为x的边只需判断min(x,x^1)是否被访问过就行了。
2.图不一定连同。做完一次dfs后在扫一遍看一下有没有dfn[0]还为0的点。
/**
双连通找桥
桥的判定条件:对于一条边(u,v) low[v] > dfn[u]
*/
#include <iostream>
#include<cstring>
#define maxn 600000
#include<map>
#include<stack>
#include<stdio.h>
#include<cstring>
#include<algorithm>
using namespace std;
int n,m;//点数,边数
int cc; //边数
int ti; //时间
int cnt; //不同点数
int ans_cnt; //桥数
int bcnt; //染色标号
int stop; //栈指针
int dfn[maxn];
int low[maxn];
int vis[maxn]; //标记重边
int ans[maxn];
int instack[maxn]; //标记是否在栈中
int first[maxn];
int next[maxn];
int stap[maxn]; //模拟栈
int belong[maxn]; //某个点所属的连同分量
map<string,int>map1;
map<int,string>map2;
struct Edge
{
int u,v;
};
Edge edge[maxn];
void init()
{
stop = 0;
cc = 0;
ti = 0;
cnt = 0;
ans_cnt = 0;
bcnt = 0;
memset(instack,0,sizeof instack);
memset(dfn,0,sizeof dfn);
memset(first,-1,sizeof first);
memset(next,-1,sizeof next);
memset(low,0,sizeof low);
memset(vis,0,sizeof vis);
map1.clear();
map2.clear();
}
void add_edge(int u,int v)
{
edge[cc].u = u;
edge[cc].v = v;
next[cc] = first[u];
first[u] = cc;
cc++;
}
void tarjan(int u,int fa)
{
dfn[u] = low[u] = ++ti;
instack[u] = 1;
stap[++stop]=u;
for(int i = first[u]; i != -1; i = next[i])
{
int v = edge[i].v;
int x= min(i,i ^ 1);
if(!vis[x])
{
vis[x] = 1;
if(dfn[v]==0)
{
tarjan(v,u);
low[u] = min(low[u],low[v]);
if(low[v] > dfn[u])
{
ans[++ans_cnt] = i;
}
}
else if(low[u] > dfn[v])
{
low[u] = dfn[v];
}
}
int j;
if (dfn[u]==low[u])
{
bcnt++;
do
{
j=stap[stop--];
instack[j]=false;
belong[j]=bcnt;
}
while (j!=u);
}
}
}
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
scanf("%d %d",&n,&m);
init();
int cnt = 0;
for(int i = 1; i <= m; i++)
{
char temp1[20],temp2[20];
scanf("%s %s",temp1,temp2);
if(map1.find(temp1) == map1.end())
{
map1[temp1] = ++cnt;
map2[cnt] = temp1;
}
if(map1.find(temp2) == map1.end())
{
map1[temp2] = ++cnt;
map2[cnt] = temp2;
}
int u = map1[temp1];
int v = map1[temp2];
add_edge(u,v);
add_edge(v,u);
}
tarjan(1,-1);
for(int i = 1; i <= n; i++)
{
if(dfn[i] == 0)
{
ans_cnt = 0;
break;
}
}
printf("%d\n",ans_cnt);
sort(ans+1,ans+ans_cnt+1);
for(int i = 1; i <= ans_cnt; i++)
{
int x = ans[i];
x = min(x,x^1);
int u = edge[x].u;
int v = edge[x].v;
printf("%s %s\n",map2[u].c_str(),map2[v].c_str());
}
}
return 0;
}