连通类经典题
题意及分析参考:
1.建反向图 2.tarjan 算法求割点3.二部图与奇圈 4.交叉染色
http://blog.csdn.net/lyy289065406/article/details/6756821
算法:
无向图寻找割点的 tarjan 算法,叉分染色。
目标:
找出图中所有的奇圈(点数大于 3),并标记在圈上的点,最后计算出未被标记的点数。
PS:
记得找到奇圈才是关键: low[v] >= dfn[u] ( tarjan 算法 )
做完这道题,很累,真的自己想不出来,后来发现,自己把 tarjan 算法的几个关键都托付给模板了。。。(有向图、无向图的割点、桥)
// zstu_wangrui 2942 Accepted 4236K 1094MS C++ 2397B 2013-08-02 19:02:41
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn = 1010;
int min( int a, int b ){ return a < b ? a : b; }
int max( int a, int b ){ return a > b ? a : b; }
struct Edge{
int v, sign, next;
}edge[maxn*maxn];
int tot, head[maxn];
struct EE{
int u, v;
EE(){}
EE( int a, int b ) : u(a), v(b){}
}st[maxn];
int top;
int n, r, E[maxn][maxn];
void init()
{
memset(E, -1, sizeof(E));
tot = 0;
memset(head, -1, sizeof(head));
}
void add_edge( int u, int v )
{
edge[tot].v = v;
edge[tot].sign = 0;
edge[tot].next = head[u];
head[u] = tot++;
edge[tot].v = u;
edge[tot].sign = 0;
edge[tot].next = head[v];
head[v] = tot++;
}
int color[maxn], ans, flag, In[maxn], vis[maxn];
void dfs( int u, int p, int col )
{
color[u] = col;
int i, v;
for(i = head[u]; i != -1; i = edge[i].next)
{
v = edge[i].v;
if(vis[v])
{
if(color[v] == -1)
dfs( v, u, !col );
else if(color[v] == color[u])
flag = 1;
if(flag)return ;
}
}
}
int tmpdfn, dfn[maxn], low[maxn];
void tarjan( int u )
{
low[u] = dfn[u] = tmpdfn++;
int i, v, j;
EE t;
for(i = head[u]; i != -1; i = edge[i].next)if(!edge[i].sign)
{
v = edge[i].v;
edge[i].sign = edge[i^1].sign = 1;
if(dfn[v] == -1)
{
EE temp( u, v );
st[top++] = temp;
tarjan( v );
low[u] = min( low[u], low[v] );
if(low[v] >= dfn[u]) //割点
{
memset(vis, 0, sizeof(vis));
do{
t = st[--top];
vis[t.u] = vis[t.v] = 1;
}while( top >= 0 && !(t.u == temp.u && t.v == temp.v) );
flag = 0;
memset(color, -1, sizeof(color));
dfs( u, u, 1 );
if(flag)for(j = 1; j <= n; j++)if(vis[j])
In[j] = 1;
}
if( low[v] > dfn[u] );//桥
}
else low[u] = min( low[u], dfn[v] );
}
if( low[u] == dfn[u] );//缩点时刻
}
void SCC()
{
int i;
top = 0;
tmpdfn = 1;
memset(dfn, -1, sizeof(dfn));
for(i = 1; i <= n; i++)if(dfn[i] == -1)tarjan( i );
}
int main()
{
int u, v, i, j;
while( ~scanf( "%d%d", &n, &r ), n + r )
{
init();
while( r-- )
{
scanf( "%d%d", &u, &v );
E[u][v] = E[v][u] = 0;
}
for(u = 1; u <= n; u++)for(v = u + 1; v <= n; v++)if(E[u][v])
add_edge( u, v );
memset(In, 0, sizeof(In));
SCC();
ans = 0;
for(i = 1; i <= n; i++)if(In[i])
ans++;
printf( "%d\n", n - ans );
}
return 0;
}