题目大意:公园有n个景点,公园的管理员要计划修建m条能形成环形的观光路径。此时,如果一条路径没有被任何一个环路所使用,它就是不需要的边,多余边;如果一个路径被多余一个环路所使用,那它就是冲突边;求多余边和冲突边的个数。
思路分析:
①:多余边:即是双连通的割边;
②:冲突边:把图分成多个块,求块里的边数,如果块里的边数大于点数,就说明这个块里的边都是冲突边;如何理解呢,如果一个块中的边多余点数,就说明有边把最外边的大环分割成了几个小环,那么小环和小环之间,小环和大环之间就会形成公用边,进而块里的环也就都是冲突边了。
代码实现:
#include<cstdio>
#include<cstring>
#include<vector>
#include<queue>
#include<stack>
#include<cmath>
#include<algorithm>
#include<iostream>
//#pragma comment(linker, "/STACK:102400000,102400000")
#define Min(a,b) ((a)<(b)?(a):(b))
#define Max(a,b) ((a)>(b)?(a):(b))
#define MEM(a) (memset((a),0,sizeof(a)))
#define MEME(a) (memset((a),-1,sizeof(a)))
#define MEMX(a) (memset((a),0x3f,sizeof(a)))
using namespace std;
const int N=10005;
const int M=100005;
int dfn[N],low[N],vis[N],block[N],st[N],bccn,top,s_top,tim,ans1,ans2,cnt,n,m;
bool in[N];
struct Edge{
int v;
Edge *next;
}*head[N],e[M*2];
void Addedge(int from,int to){
Edge *p=&e[top++];
p->v=to;
p->next=head[from];
head[from]=p;
}
void Find_edge(){
int sum=0,u,v;
for(int i=1;i<=cnt;++i){
u=block[i];
for(Edge *p=head[u];p;p=p->next){
if(in[p->v]) sum++;
}
}
sum/=2;
if(sum>cnt) ans2+=sum;
}
void Tarjan_bcc(int u,int fa){
dfn[u]=low[u]=++tim;
st[++s_top]=u;
int v,tmp;
for(Edge *p=head[u];p;p=p->next){
v=p->v;
if(v==fa) continue;
if(!dfn[v]){
Tarjan_bcc(v,u);
low[u]=Min(low[u],low[v]);
if(low[v]>dfn[u]) ans1++;
if(low[v]>=dfn[u]){
cnt=0;
memset(in,0,sizeof(in));
do{
tmp=st[s_top--];
block[++cnt]=tmp;
in[tmp]=1;
}while(tmp!=v);
block[++cnt]=u;
in[u]=1;
Find_edge();
}
}else low[u]=Min(low[u],dfn[v]);
}
}
int main(){
int a,b;
while(~scanf("%d%d",&n,&m),(n||m)){
MEM(head),MEM(dfn),MEM(low),MEM(block),MEM(in);
bccn=top=s_top=ans1=ans2=tim=0;
for(int i=1;i<=m;++i){
scanf("%d%d",&a,&b);
Addedge(a,b);
Addedge(b,a);
}
for(int i=0;i<n;++i) if(!dfn[i]) Tarjan_bcc(i,-1);
printf("%d %d\n",ans1,ans2);
}
}