题意:
求缩点后(度为1的点的个数+1)/2的值
人生的第一个双连通缩点的题诞生了!
(自己写的常数爆炸的版本。。
下一题改一下板子嗯
理解双联通用栈的原理用题上的数据在草稿纸上过一遍就好了
边双联通和无向图的可达性一样是等价关系
关于tarjan的原理建议看训练指南
-----------------------------code------------------------------------
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
#include<stack>
#include<set>
using namespace std;
const int maxn = 1123;
vector<int> edge[maxn];
stack<int> S;
set<int> is;
int dfn[maxn],low[maxn],_cnt;
int belong[maxn];
void Link(int st,int ed){
edge[st].push_back(ed);
}
void init(){
for(int i=0;i<maxn;i++)
edge[i].clear();
while(S.empty()==false)
S.pop();
is.clear();
memset(dfn,-1,sizeof(dfn));
memset(low,-1,sizeof(low));
memset(belong,-1,sizeof(belong));
_cnt = 1;
}
#define debug(a,b) out(#a,a,b)
void out(char *name,int *s,int n){
puts(name);
for(int i=1;i<=n;i++)
printf(i<n?"%d ":"%d\n",s[i]);
}
void dfs(int st,int fa){
S.push(st);
dfn[st] = low[st] = _cnt++;
for(vector<int>::iterator it = edge[st].begin();it!=edge[st].end();it++){
int x = *it;
if(x != fa){
if(dfn[x] == -1){
dfs(x,st);
low[st] = min(low[st],low[x]);
}
else{
low[st] = min(low[st],dfn[x]);
}
}
}
if(dfn[st] == low[st]){
while(S.top() != st){
belong[S.top()] = st;
S.pop();
}
S.pop();
belong[st] = st;
is.insert(st);
}
}
int ind[maxn];
int main(){
int n,m;
while(~scanf("%d %d",&n,&m)){
init();
int x,y;
while(m--){
scanf("%d %d",&x,&y);
Link(x,y);
Link(y,x);
}
dfs(1,-1);
memset(ind,0,sizeof(ind));
for(int i=1;i<=n;i++){
for(vector<int>::iterator it = edge[i].begin();it!=edge[i].end();it++){
int v = *it;
if(belong[v] != belong[i]){
ind[belong[v]] ++;
ind[belong[i]] ++;
}
}
}
// debug(belong,n);
// debug(dfn,n);
// debug(low,n);
// debug(ind,n);
int cnt = 1;
for(int i=1;i<=n;i++){
if(ind[i] == 2 && is.find(i) != is.end()){
cnt++;
// printf("i = %d\n",i);
}
}
printf("%d\n",cnt/2);
}
return 0;
}