大意: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;
}

本文探讨了一种特殊场景下的图论问题——如何通过剔除最少数量的人来确保特定条件下的人群能在圆桌上就座而不会违反既定规则。通过对问题进行抽象,将其转化为点的双联通性分析,并利用Tarjan算法检测并处理桥接点,最终实现对奇数个节点组成的环的有效判断。
963

被折叠的 条评论
为什么被折叠?



