您的位置:首页 > 其它

UVALive3523 [Knights of the Round Table] tarjan求无向图双联通分量

2017-08-25 13:39 639 查看

题目链接

题意:有n个骑士经常举行圆桌会议,商讨大事。每次圆桌会议至少应有3个骑士参加,且相互憎恨的骑士不能坐在圆桌旁的相邻位置。如果发生意见分歧,则需要举手表决,因为骑士不能保证每次提议都一致通过,因此参加会议的骑士数目必须是奇数,以防止赞同和反对票一样多。知道哪些骑士相互憎恨之后,你的任务是统计有多少个骑士不可能参加任何一个会议。

solution:

以骑士为节点建图(不互相憎恨的骑士之间连边,表示可以坐在相邻位置)

原问题就可以转化为求不在任意一个奇圈(节点有奇数个的圈)的点的数量

因为二分图不含奇圈,如果一个双联通分量是二分图,则只需要找出图中的

双联通分量,在判断是否为二分图,就可以算出答案了。

ps:含有奇圈的双联通分量中的每一个点都属于至少一个奇圈。

解释一下:



U1,U2 属于同一个奇圈

因为是双联通分量,所以v与U1,U2都连通。

因为是奇圈,所以U1到U2的两条路长度为一奇一偶。

所以无论黄线长为奇数或偶数,v,U1,U2组成的圈中一定有一个奇圈。

#include <stack>
#include <vector>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iostream>
using namespace std;
const int N = 1e3 + 7;

struct Edge{ int u, v; };

stack<Edge> S;
vector<int> G
, bcc
;
int dfn
, low
, pos
, bcc_cnt, id;
int col
, odd
;

void dfs(int u, int fa){
dfn[u]=low[u]=++id;
for ( int i=0; i<G[u].size(); i++ ){
int v=G[u][i];
if( v==fa ) continue;
Edge e=(Edge) { u, v };
if( !dfn[v] ){
S.push(e);
dfs(v, u);
low[u]=min(low[u], low[v]);
if( dfn[u]<=low[v] ){
bcc[++bcc_cnt].clear();
for(;;){
Edge x=S.top(); S.pop();
if( pos[x.v]!=bcc_cnt ) {pos[x.v]=bcc_cnt; bcc[bcc_cnt].push_back(x.v); }
if( pos[x.u]!=bcc_cnt ) {pos[x.u]=bcc_cnt; bcc[bcc_cnt].push_back(x.u); }
if( x.u==u && x.v==v ) break;
}
}
}else if( dfn[v]<low[u] ){
S.push(e);
low[u]=min(low[u],dfn[v]);
}
}
}

void find_bcc(int n){
memset(dfn,0,sizeof(dfn));
memset(low,0,sizeof(low));
memset(pos,0,sizeof(pos));
bcc_cnt=id=0;
for ( int i=1; i<=n; i++ )
if( !dfn[i] ) dfs(i, 0);
}

bool bipartite(int u, int b){
for ( int i=0; i<G[u].size(); i++ ){
int v=G[u][i];
if( pos[v]!=b ) continue;
if( col[v]==col[u] ) return false;
if( !col[v] ){
col[v]=3-col[u];
if( !bipartite(v, b) ) return false;
}
}
return true;
}
int A

;
int main(){
int n, m;
while( scanf("%d%d", &n, &m )!=EOF &&n ){
for ( int i=0; i<=n; i++ ) G[i].clear();
memset(A,0,sizeof(A));
for ( int i=1; i<=m; i++ ){
int x, y;
scanf("%d%d", &x, &y );
A[x][y]=A[y][x]=1;
}
//  printf("\n");
for ( int i=1; i<=n; i++ )
for ( int j=i+1; j<=n; j++ )
if( !A[i][j] ) /*printf("%d %d\n", i, j),*/ G[i].push_back(j), G[j].push_back(i);
find_bcc(n);
//  printf("\n");
/*  for ( int i=1; i<=bcc_cnt; i++ ){
for ( int j=0; j<bcc[i].size(); j++ )
printf("%d ", bcc[i][j] );
printf("\n");
}
*/
memset(odd,0,sizeof(odd));
memset(pos,0,sizeof(pos));
//  printf("\n");
for ( int i=1; i<=bcc_cnt; i++ ){
memset(col,0,sizeof(col));
for ( int j=0; j<bcc[i].size(); j++ ) pos[bcc[i][j]]=i;
//      printf("%d\n", bcc[i].size() );

int u=bcc[i][0];
col[u]=1;
if( !bipartite(u,i)){
//              printf("%d\n", i);
for ( int j=0; j<bcc[i].size(); j++ ) odd[bcc[i][j]]=1;
}

//      printf("\n");
}
//  printf("\n");
int ans=n;
for ( int i=1; i<=n; i++ ) if( odd[i] ) ans--;
printf("%d\n", ans );
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: