poj 2942 Knights of the Round Table
http://poj.org/problem?id=2942
题目大意:N个骑士中某些骑士之间会有仇恨。骑士们开会时围坐在一个圆桌旁。一次会议能够举行,当且仅当没有相邻的两个骑士相互仇恨,且开会人数为大于2的奇数。若某个骑士任何会议都不能参加,那么就必须将它踢出。给出骑士之间的仇恨关系,问需要踢出多少个骑士。
思路:题目给出的是一对对相互仇恨的骑士,要使得骑士间环成一环,相邻没有仇恨,就要建图的时候就不能出现相邻有仇恨的。然后问题转化成求一个图里面的奇环,而在一个双连通图里,如果存在一个奇环,则这个双连通图中的每一个点,都能在一个奇环里(很蛋疼的想法)。所以最后就是在一个双连通图里找奇环,利用正负标记可以很容易求出。

#include<set> #include<map> #include<stack> #include<queue> #include<cmath> #include<bitset> #include<string> #include<climits> #include<cstdio> #include<vector> #include<utility> #include<cstdlib> #include<cstring> #include<iostream> #include<algorithm> #define IN puts("in") #define OUT puts("out") #define FR(x) freopen(x,"r",stdin) #define FW(x) freopen(x,"w",stdout) #define MSET(x,y) memset(x,y,sizeof(x)) #define ST system("pause") using namespace std; const int maxn = 1005; struct nd { int u,v,next; }edge[maxn*maxn]; int head[maxn],vis[maxn],dfn[maxn],low[maxn],st[maxn],as[maxn],flag[maxn],bs[maxn][maxn],belg[maxn],color[maxn]; int ecnt,cnt,idx,tp; void add(int u,int v) { edge[ecnt].u = u; edge[ecnt].v = v; edge[ecnt].next = head[u]; head[u] = ecnt++; } int judge(int u,int f) { int i,v; color[u] = f; for(i = head[u]; i != -1; i = edge[i].next) { v = edge[i].v; if(belg[v]==cnt) { if(color[v]==color[u])return 1; if(!color[v]&&judge(v,-f))return 1; } } return 0; } void tarjan(int pre,int u) { int i,v,t,k,j; dfn[u] = low[u] = ++idx; vis[u] = 1; st[++tp] = u; for(i = head[u]; i != -1; i = edge[i].next) { v = edge[i].v; if(v==pre)continue; if(!dfn[v]){ tarjan(u,v); low[u] = min(low[v],low[u]); if(low[v]>=dfn[u]){ k = t = 0; cnt++; do{ j = st[tp--]; as[++k] = j; belg[j] = cnt; vis[j] = 0; }while(v!=j); as[++k] = u; MSET(color,0); if(k>=3&&judge(u,1)) while(k)flag[as[k--]]=0; } }else if(vis[v])low[u] = min(dfn[v],low[u]); } } void processing(int n,int m) { int i,j,k,u,v; for(i = 0; i < m; ++ i) { scanf("%d %d",&u,&v); bs[u][v] = bs[v][u] = 0; } for(i = 1; i <= n; ++ i) for(j = 1 + i; j <= n; ++ j) if(bs[i][j]) add(i,j),add(j,i); for(i = 1; i <= n; ++ i) if(!dfn[i])tarjan(-1,i); k = 0; for(i = 1; i <= n; ++ i)if(flag[i])k++; printf("%d\n",k); } void init() { ecnt = cnt = idx = tp = 0; MSET(head,-1); MSET(vis,0); MSET(dfn,0); MSET(flag,-1); MSET(bs,-1); MSET(belg,-1); } int main() { int n,m; while(scanf("%d %d",&n,&m)==2) { if(n+m==0)break; init(); processing(n,m); } return 0; }