您的位置:首页 > 其它

poj 2942 双连通分量+二分图的染色判断

2016-05-21 16:52 417 查看
这道题是一道综合性比较强的图论题,题意是
亚瑟王要在圆桌上召开骑士会议,为了不引发骑士之间的冲突,并且能够让会议的议题有令人满意的结果,每次开会前都必须对出席会议的骑士有如下要求:

1、 相互憎恨的两个骑士不能坐在直接相邻的2个位置;

2、 出席会议的骑士数必须是奇数,这是为了让投票表决议题时都能有结果。

如果出现有某些骑士无法出席所有会议(例如这个骑士憎恨所有的其他骑士),则亚瑟王为了世界和平会强制把他剔除出骑士团。

现在给定准备去开会的骑士数n,再给出m对憎恨对(表示某2个骑士之间使互相憎恨的),问亚瑟王至少要剔除多少个骑士才能顺利召开会议?

注意:1、所给出的憎恨关系一定是双向的,不存在单向憎恨关系。

2、由于是圆桌会议,则每个出席的骑士身边必定刚好有2个骑士。即每个骑士的座位两边都必定各有一个骑士。

3、一个骑士无法开会,就是说至少有3个骑士才可能开会。

我的理解是是先判断割点,然后再利用二分图无奇圈的性质判断连通分量是否为偶圈,给出一组比较难过的测试数据:

6 8
1 4
1 5
1 6
2 4
2 5
2 6
3 6
4 5
0 0

代码如下:
#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
#define MAXN 1004
#define MAXM 1001000
#define min(a,b) (a)<(b)?(a):(b)
int n,m,tot,count,top;
int first[MAXN],DFN[MAXN],Low[MAXN],vis[MAXN],col[MAXN],mark[MAXN],stack[MAXM],odd[MAXN];
int G[MAXN][MAXN];
struct Edge
{
int st,to,next,vis;
}edge[2*MAXM];
void addedge(int a,int b)
{
edge[tot].to=b;
edge[tot].st=a;
edge[tot].next=first[a];
edge[tot].vis=0;
first[a]=tot++;
}
int find(int s)
{
int i;
for(i=first[s];i!=-1;i=edge[i].next)
{
int t=edge[i].to;
if(mark[t])
{
if(col[t]==-1)
{
col[t]=!col[s];
return find(t);
}
else if(col[t]==col[s]) return 1;
}
}
return 0;
}
void color(int s)
{
int i;
memset(mark,0,sizeof(mark));
do{
i=stack[top--];
mark[edge[i].st]=1;
mark[edge[i].to]=1;
}while(edge[i].st!=s);
memset(col,-1,sizeof(col));
col[s]=0;
if(find(s))
{
for(i=1;i<=n;i++)
{
if(mark[i])
odd[i]=1;
}
}
}
void dfs(int s)
{
int i,v;
DFN[s]=Low[s]=++count;
for(i=first[s];i!=-1;i=edge[i].next)
{
v=edge[i].to;
if(edge[i].vis)continue;
edge[i].vis=edge[i^1].vis=1;
stack[++top]=i;
if(!DFN[v])
{
dfs(v);
Low[s]=min(Low[s],Low[v]);  //到此可以判断是否形成局部图中的一个双联通分量
if(Low[v]>=DFN[s])color(s);  //判断割点,并进入连通分量
}
else
{
Low[s]=min(Low[s],DFN[v]);
}
}
}
int main()
{
while(scanf("%d%d",&n,&m),n||m)
{
int i,j;
memset(G,0,sizeof(G));
for(i=1;i<=m;i++)
{
int a,b;
scanf("%d%d",&a,&b);
G[a][b]=1;
G[b][a]=1;
}
tot=0;
memset(first,-1,sizeof(first));
for(i=1;i<=n;i++)
{
for(j=i+1;j<=n;j++)
{
if(G[i][j]==0)
{
addedge(i,j);
addedge(j,i);
}
}
}
memset(DFN,0,sizeof(DFN));
memset(odd,0,sizeof(odd));
count=0;top=0;
for(i=1;i<=n;i++)
{
if(!DFN[i])
dfs(i);
}
int ans=0;
for(i=1;i<=n;i++)
{
if(!odd[i])
ans++;
}
printf("%d\n",ans);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: