题意:给定n个点m条边。这些边的意思为 u和v是相互仇恨的关系
要求满足一下条件。
1)一个人的周围不能有仇恨关系的人,这些人围成一个圆圈,每个点有两个邻居。
2)会议的是由三个人以上组成,开会议的人数必须是奇数。
要求出必须剔除几个人。
在做本题的过程中我查询了一些其他博客的做法。
本题需要的知识
1)补图(已知G求~G)
2)奇圈的定义(顶点个数为奇数的圈,但也有部分人说是边的个数为奇数的圈)
3)两个定理
1.如果一个双连通分量内的某些顶点在一个奇圈中(即双连通分量含有奇圈),那么这个双连通分量的其他顶点也在某个奇圈中;
2.如果一个双连通分量含有奇圈,则他必定不是一个二分图。反过来也成立,这是一个充要条件。
可以通过下面这个例子来理解这两定理
1–>2
1–>3
1–>4
3–>4
2–>4
{1,2,3,4}是一个点双连通分量,它有偶数个点,但是它有两个奇圈,能出席两次会议
4)求点双连通分量(tarjan相关算法的知识)
5)二分图的判定(交叉染色法)
其他:显然在只要某个点双连通分量不是二分图那么它必定包含奇圈,那么这个点双连通分量中的所有点都可以出席会议。由于割点一定属于某个强连通分量,如果直接算的话可能会算重,所以标记,最后一起算。
更详细内容见:http://blog.csdn.net/lyy289065406/article/details/6756821#quote
#include <iostream> #include <cstdio> #include <cstring> #include <cmath> #include <set> #include <vector> #include <map> #include <queue> #include <set> #include <algorithm> using namespace std; #define MAXN 1010 vector <int> e[MAXN]; vector <int> bck[MAXN];
int dfn[MAXN],low[MAXN],sta[MAXN*2]; int times,top; int ssum,n,m; char map1[MAXN][MAXN]; char can[MAXN]; char vis[MAXN]; char inbck[MAXN]; void tarjan_4(int u){ sta[++top]=u; dfn[u]=low[u]=++times; for(int i=0;i<(int)e[u].size();i++){ int v=e[u][i]; if(!dfn[v]){ tarjan_4(v); low[u]=min(low[u],low[v]); if(dfn[u]<=low[v]){ do { bck[ssum].push_back(sta[top]); }while(sta[top--]!=v); bck[ssum].push_back(u); ++ssum; } } else low[u]=min(low[u],dfn[v]); } } bool checkdfs(int u,int color){ vis[u]=color; for(int i=0;i<(int)e[u].size();i++){ int v=e[u][i]; if(!inbck[v])continue; if(vis[v]==-1){ if(!checkdfs(v,!color))return false; } else if(vis[u]==vis[v])return false; } return true; } void solve(){ ssum=top=times=0; for(int i=0;i<MAXN;i++)bck[i].clear(); memset(dfn,0,sizeof(dfn)); memset(low,0,sizeof(low)); memset(can,0,sizeof(can)); for(int i=1;i<=n;i++) if(!dfn[i])tarjan_4(i);
for(int i=0;i<ssum;i++){ int tmp=bck[i].size(); memset(inbck,0,sizeof(inbck)); for(int j=0;j<tmp;j++){ inbck[bck[i][j]]=1; }
memset(vis,-1,sizeof(vis)); if(!checkdfs(bck[i][0],0)){ for(int j=0;j<tmp;j++){ can[bck[i][j]]=1; } } } int ans=0; for(int i=1;i<=n;i++){ if(!can[i])ans++; } printf("%d\n",ans); }
int main() { while(~scanf("%d%d",&n,&m)&&(n||m)){ for(int i=0;i<n+10;i++)e[i].clear(); memset(map1,0,sizeof(map1)); for(int i=0,x,y;i<m;i++){ scanf("%d%d",&x,&y); map1[x][y]=map1[y][x]=1; } for(int i=1;i<=n;i++) for(int j=i+1;j<=n;j++) if(!map1[i][j]) { e[i].push_back(j); e[j].push_back(i); }
solve(); } return 0; }
|