lightoj 1300 边双联通分量+交叉染色求奇圈

时间:2023-03-09 05:29:24
lightoj 1300 边双联通分量+交叉染色求奇圈

题目链接:http://lightoj.com/volume_showproblem.php?problem=1300

边双连通分量首先dfs找出桥并标记,然后dfs交叉着色找奇圈上的点。这题只要求在奇圈上的点个数。容易得到,一个边双联通分量如果存在奇圈,那么整个分量上的点都属于某个奇圈。

#include<cstdio>
#include<cstring>
#include<cmath>
#include<iostream>
#include<algorithm>
#include<queue>
#include<vector>
using namespace std;
const int maxn = ;
const int maxe = ;
const int INF = 0x3f3f3f; int pre[maxn],low[maxn],dfs_clock;
bool isbridge[maxe*]; struct Edge{
int u,v;
int next;
Edge(int u=,int v=,int next=): u(u) , v(v), next(next) {}
}edges[maxe*];
int head[maxn],cnt; int color[maxn]; //用交叉染色法进行判断奇圈;
bool flag;
int n,m;
int ans,tempans; void tarjan(int u,int fa){
pre[u] = low[u] = dfs_clock++;
for(int i=head[u];i!=-;i=edges[i].next){
int v = edges[i].v;
if(!pre[v]){
tarjan(v,u);
low[u] = min(low[u],low[v]);
if(low[v] > pre[u]) { isbridge[i] = true; isbridge[i^] = true; }
}
else if(pre[v] < pre[u] && v != fa) //u->v是反向边;
low[u] = min(low[u],pre[v]);
}
} void dfs_paint(int u,int fa_c){
color[u] = fa_c;
tempans++;
for(int i=head[u];i!=-;i=edges[i].next){
if(isbridge[i]) continue; //访问到桥跳过;
int v = edges[i].v;
if(!color[v]) dfs_paint(v,-fa_c); //还没有染色;
else if(color[u] == color[v])
flag = true;
}
} void addedge(int u,int v){
edges[cnt] = Edge(u,v,head[u]);
head[u] = cnt++;
}
int main()
{
// freopen("E:\\acm\\input.txt","r",stdin);
int T;
cin>>T;
for(int t=;t<=T;t++){
cin>>n>>m;
memset(head,-,sizeof(head));
cnt = ;
for(int i=;i<=m;i++){
int a,b;
scanf("%d %d",&a,&b);
edges[cnt] = Edge(a,b,head[a]);
head[a] = cnt++;
edges[cnt] = Edge(b,a,head[b]);
head[b] = cnt++;
//addedge(a,b);
//addedge(b,a);
}
dfs_clock = ;
memset(pre,,sizeof(pre));
memset(isbridge,,sizeof(isbridge));
for(int i=;i<n;i++)
if(!pre[i]) tarjan(i,-); memset(color,,sizeof(color));
ans = ;
for(int i=;i<n;i++){
if(!color[i]){
flag = false;
tempans = ;
dfs_paint(i,); //交叉染色法
if(flag)
ans += tempans;
}
}
printf("Case %d: %d\n",t,ans);
}
}