hiho詳解鏈接:http://hihocoder.com/contest/hiho55/problem/1
點的雙連通分量的定義:對於一個無向圖的子圖,當刪除其中任意一個點後,不改變圖內點的連通性,這樣的子圖叫做點的雙連通子圖。而當子圖的邊數達到最大時,叫做點的雙連通分量。
可以知道的是,橋一定是點的雙連通分量。
void pop_stack(int x)//邊不斷出棧並標記,直到編號x的邊離開棧爲止
{
num_node++;
int len = 0,minn = x;
e_vis[x] = 1;
while(top > 0 && sta[top] != x)
{
fuben[len++] = sta[top];
e_vis[sta[top]] = 1;//不斷標記邊
minn = min(minn,sta[top]);//本題要求,記錄同一組內邊標號的最小值,可省略
top--;
}
top--;
fuben[len++] = x;
for(int i = 0;i < len;i++)
mark[fuben[i]] = minn;//標記原邊所在的組,可省略
}
//dfs_pos爲dfs序,low爲最近祖先的dfs序,這裏的邊中要多加個變量id來便於邊的標記
//vis爲這個點有沒被訪問
void tarjan(int u,int pre)
{
int son_num = 0;
int v;
vis[u] = 1;
dfs_pos[u] = low[u] = ++jilu;//jilu爲從的dfs序
for(int i = head[u];~i;i = e[i].nex)
{
v = e[i].v;
if(e_vis[e[i].id])continue;//如果邊被訪問過則跳過,
if(!vis[v]){
sta[++top] = e[i].id;
son_num++;
tarjan(v,u);
low[u] = min(low[u],low[v]);
/*if(pre == -1 && son_num > 1){
pop_stack(e[i].id);
}*///這題並不需要這句話,某些題目判斷時可能需要
if(low[v] >= dfs_pos[u]){
pop_stack(e[i].id);//邊的出棧處理操作
}
}else if(v != pre){
sta[++top] = e[i].id;
low[u] = min(low[u],low[v]);
}
}
}
hiho原題的題解代碼:
#include <bits/stdc++.h>
#define mem(a,b) memset(a,b,sizeof(a))
#define pii pair<int,int>
typedef long long ll;
using namespace std;
const int maxn = 250005;
struct ppp
{
int v,nex,id;
}e[maxn];
int head[maxn / 10],tole,n,m,vis[maxn / 10],jilu;
int dfs_pos[maxn / 10],low[maxn / 10];
int mark[maxn],e_vis[maxn],top;
void make_edge(int u,int v,int id)
{
e[tole].id = id;e[tole].v = v;e[tole].nex = head[u];head[u] = tole++;
}
int sta[maxn];
int fuben[maxn];
int num_node;
void pop_stack(int x)//邊不斷出棧並標記,直到編號x的邊離開棧爲止
{
num_node++;
int len = 0,minn = x;
e_vis[x] = 1;
while(top > 0 && sta[top] != x)
{
fuben[len++] = sta[top];
e_vis[sta[top]] = 1;//不斷標記邊
minn = min(minn,sta[top]);//本題要求,記錄同一組內邊標號的最小值,可省略
top--;
}
top--;
fuben[len++] = x;
for(int i = 0;i < len;i++)
mark[fuben[i]] = minn;//標記原邊所在的組,可省略
}
//dfs_pos爲dfs序,low爲最近祖先的dfs序,這裏的邊中要多加個變量id來便於邊的標記
//vis爲這個點有沒被訪問
void tarjan(int u,int pre)
{
int son_num = 0;
int v;
vis[u] = 1;
dfs_pos[u] = low[u] = ++jilu;//jilu爲從的dfs序
for(int i = head[u];~i;i = e[i].nex)
{
v = e[i].v;
if(e_vis[e[i].id])continue;//如果邊被訪問過則跳過,
if(!vis[v]){
sta[++top] = e[i].id;
son_num++;
tarjan(v,u);
low[u] = min(low[u],low[v]);
/*if(pre == -1 && son_num > 1){
pop_stack(e[i].id);
}*///這題並不需要這句話,某些題目判斷時可能需要
if(low[v] >= dfs_pos[u]){
pop_stack(e[i].id);//邊的出棧處理操作
}
}else if(v != pre){
sta[++top] = e[i].id;
low[u] = min(low[u],low[v]);
}
}
}
int main()
{
while(~scanf("%d%d",&n,&m))
{
tole = 0;mem(head,-1);mem(vis,0);mem(e_vis,0);
num_node = 0;
for(int i = 1,a,b;i <= m;i++)
{
scanf("%d%d",&a,&b);
make_edge(a,b,i);
make_edge(b,a,i);
}
top = 0;jilu = 0;mem(mark,0);
tarjan(1,-1);
printf("%d\n",num_node);
for(int i = 1;i <= m;i++)
{
if(i > 1)printf(" ");
cout<<mark[i];
}
printf("\n");
}
}