大意:m个关系的人之间不能再圆桌上坐在相邻的位置上。并且人数为奇数,问至少踢出多少人能够开会。
思路:因为人是围着圆桌坐,所以每人的度肯定是2,即度为1和0(单独一人)的都要被踢除。那么可以抽象为点的双联通。在出现桥的时候(即度数为1)将该联通块的人都统计下来,判断是不是奇环(二分染色)(PS:说明为啥不能直接统计个数判断奇环呢?既然是点的双联通那么一定是环,是不是能够直接判断当前的人数就能下是奇环的定论呢? 答案是否定的!因为联通块可能由多个奇环组成!)
#include<map> #include<queue> #include<cmath> #include<cstdio> #include<stack> #include<iostream> #include<cstring> #include<algorithm> #define LL int #define inf 0x3f3f3f3f #define eps 1e-8 #include<vector> #define ls l,mid,rt<<1 #define rs mid+1,r,rt<<1|1 using namespace std; const int Ma = 1100; struct node{ int to,w,next; }q[Ma*Ma]; bool mp[1100][1100]; int head[Ma*Ma],dfn[Ma],stk[Ma*5],vis[Ma],low[Ma],tmp[Ma],col[Ma],part[Ma]; int cnt,top,tim,scc,sum,n,ans,mark[Ma]; void Add(int a,int b){ q[cnt].to = b; q[cnt].next = head[a]; head[a] = cnt++; } void init(){ ans = scc = cnt = top = 0; tim = 1; memset(head,-1,sizeof(head)); memset(mp,false,sizeof(mp)); for(int i = 1;i <= n;++ i){ low[i] = dfn[i] = 0; vis[i]=mark[i] = 0; } } bool ser(int u,int co){ col[u] = co; for(int i=head[u];~i;i=q[i].next){ int v = q[i].to; if(!part[v]) continue; if(col[v] == co) return true; if(!col[v] && ser(v,-co)) return true; } return false; } void Judge(){ memset(part,0,sizeof(part)); memset(col,0,sizeof(col)); for(int i = 0;i < sum;++ i){ part[tmp[i] ] = 1; } if(ser(tmp[0],1)){ for(int i = 0;i < sum;++ i) mark[tmp[i] ] = 1; } } void Tarjan(int u,int To){ low[u] = dfn[u] = tim++; vis[u] = 1; stk[top++] = u; for(int i = head[u]; ~i ; i = q[i].next){ int v = q[i].to; if(i == (To^1)) continue; if(!vis[v]){ Tarjan(v,i); low[u] = min(low[u],low[v]); if(low[v] >= dfn[u]){ sum = 0; tmp[sum++] = u; stk[top] = -1; while( stk[top] != v ){ tmp[sum++] = stk[--top]; } Judge(); } } else low[u] = min(low[u],dfn[v]); } } int main(){ int m,i,j,k,a,b,c,cla; while(~scanf("%d%d",&n,&m)){ if(!n&&!m) break; init(); for(i = 0;i < m;++ i){ scanf("%d%d",&a,&b); mp[b][a] = mp[a][b] = true; } for(i = 1;i <= n;++ i) for(j = i+1;j <= n;++ j) if(!mp[i][j]) Add(i,j), Add(j,i); for(i = 1;i <= n;++ i) if(!dfn[i]) Tarjan(i,-1); for(i = 1;i <= n;++ i) if(mark[i]) ans++; printf("%d\n",n-ans); } return 0; }