poj 2942 求块+查找奇圈

来源:互联网 发布:淘宝秒杀显示无法购买 编辑:程序博客网 时间:2024/04/29 07:14

题意描述: 有n个骑士,现在要求骑士坐在圆桌上,相邻的两个位置不能坐有冲突的骑士,并且每个圆桌要求坐奇数个人,现在要求出有不能坐在圆桌上的人数(这里要求能坐的尽量坐)


分析:因为题目给出的是有冲突的两个人,那么我们根据题目给出的图建立一个图,两个可以坐在相邻位置的人连边,那么假设他们形成了一个简单的无向环,则很明显如果这个环上的顶点个数为奇数,那么这个环上的人可以坐在一个圆桌上,若顶点数为偶数的话,那么也很显然这些人都不能坐参加会议!如果他们形成了一个复杂的环(即环中有环),若过最大的环为奇数环,我们就直接可以安排他们按最大环上的做,若果最大环为偶数环,如果我能将其拆成若干个奇数环,那么我们就可以安排他们做奇数环个圆桌,否则他们都不能坐,其实说的那么复杂,其实就是先求出图中的双连通分量(顶点个数>=2),若双连通分量中存在奇环,那么这些人都可以坐上圆桌,否则环中的人都不能坐上圆桌,这里因为割点可能会属于多个双连通子图,那么对于割点我们需得特殊处理!!现在就是判断一个环是否存在奇环,那我通过二分染色的方法就可以解决,若染色后,出现两个相同的顶点出现相同的颜色,那么则存在奇环,否则不存在奇环!!


总结:这个人啊,一旦养成烂习惯就很难改掉,我遇到难点的题目就只是简单的想了一下,根本没有多深入的思考,想不出来就去搜别人的解题报告,这是个破习惯,得改啊,所以我在此我做个决定,下次一定绞尽脑汁去思考,我相信只有多思考才能进步得更快!!(能看懂和自己能够解决之间的差距是很大的)!!


代码如下:

#include<iostream>#include<cstdio>#include<cstring>using namespace std;const int N = 1050;int g[N][N],n;int dfn[N],low[N],st[N],index,top,vis[N];int flag[N],block[N];bool Vis[N];int Min(int a,int b){return a>b?b:a;}int bfs(int u){int que[N],head=0,tail=1;que[0]=u;flag[u]=1;    while(head!=tail){u=que[head];head=(head+1)%N;     for(int v=1;v<=n;v++)  if(g[u][v]&&vis[v])     if(flag[v]==-1) { flag[v]=(flag[u]+1)%2; que[tail]=v; tail=(tail+1)%N; }    else if(flag[v] == flag[u])   return 0;}return 1;}void Cutvedex(int u){int i;dfn[u]=low[u]=index++;st[++top]=u;for(int v=1;v<=n;v++)    if(g[u][v]){if(dfn[v]==-1){    Cutvedex(v);low[u]=Min(low[u],low[v]);    if(low[v]>=dfn[u]){memset(vis,0,sizeof(vis));block[0]=0;while(true){vis[st[top]]=1;block[++block[0]]=st[top];if(st[top--]==v)break;}vis[u]=1;block[++block[0]]=u;for( i=1;i<=n;i++)flag[i]=-1;if(!bfs(u))//表示若为一个奇环     for(i=1;i<=block[0];i++) Vis[block[i]]=1;  //标记能坐在圆桌上的人   }}else low[u]=Min(low[u],dfn[v]);}}int main (){    int m,i,j,x,y;while(scanf("%d%d",&n,&m)!=EOF){if(n==0&&m==0)break;for(i=1;i<=n;i++)     //初始化化原图for(j=1;j<=n;j++)    if(i!=j)g[i][j]=1;for(i=0;i<m;i++){scanf("%d%d",&x,&y);g[x][y]=0;g[y][x]=0;} memset(dfn,-1,sizeof(dfn));   memset(low,0,sizeof(low));memset(Vis,0,sizeof(Vis));top=0;index=1;for(i=1;i<=n;i++)if(dfn[i]==-1)        Cutvedex(i);    int res=0;for(i=1;i<=n;i++)if(Vis[i])res++;printf("%d\n",n-res);}return 0;}


原创粉丝点击