【POJ 2942】Knights of the Round Table(点双连通分量,二分图染色)
圆桌会议必须满足:奇数个人参与,相邻的不能是敌人(敌人关系是无向边)。
求无论如何都不能参加会议的骑士个数。只需求哪些骑士是可以参加的。
我们求原图的补图:只要不是敌人的两个人就连边。
在补图的一个奇圈里(由奇数个点组成的环)每个点都是可以参加的。而一个奇圈一定在点双连通分量里,所以我们把原图的每个点双连通分量找出来,然后判断是否有奇圈。用到了几个引理:
非二分图至少有一个奇圈。
点双连通分量如果有奇圈,那么每个点都在某个奇圈里(不一定是同一个)。
于是问题转化为对每个点双连通分量,判断它是不是二分图,如果不是,那就把它里面所有点都标记为可行,最后用总数减去可行的就是答案(无论如何都不能参加会议的骑士个数)。
二分图染色就是dfs,对一个点染色后,对其相邻点染上与自己不同的颜色,如果相邻点已经染过,就判断其颜色是否和自己相同,是则说明不是二分图,否则跳过该相邻点。直到全部染完。
#include<cstdio> #include<cstring> const int N = 1010; const int M = 2000010; struct Edge { int to,next; }edge[M]; int head[N],tot; int Low[N],DFN[N],Stack[N],Belong[N]; int Index,top; int block;//点双连通分量的个数 bool Instack[N]; bool can[N]; bool ok[N];//标记 int tmp[N];//暂时存储双连通分量中的点 int cc;//tmp的计数 int color[N];//染色 void addedge(int u,int v) { edge[tot].to = v;edge[tot].next = head[u];head[u] = tot++; } bool dfs(int u,int col)//染色判断二分图 { color[u] = col; for(int i = head[u];~i;i = edge[i].next) { int v = edge[i].to; if( !ok[v] )continue; if(~color[v]) { if(color[v]==col)return false; continue; } if(!dfs(v,!col))return false; } return true; } void Tarjan(int u,int pre) { int v; Low[u] = DFN[u] = ++Index; Stack[top++] = u; Instack[u] = true; for(int i = head[u];~i;i = edge[i].next) { v = edge[i].to; if(v == pre)continue; if( !DFN[v] ) { Tarjan(v,u); if(Low[u] > Low[v])Low[u] = Low[v]; if( Low[v] >= DFN[u]) { block++; int vn; cc = 0; memset(ok,false,sizeof ok); do { vn = Stack[--top]; Belong[vn] = block; Instack[vn] = false; ok[vn] = true; tmp[cc++] = vn; } while( vn!=v ); ok[u] = 1; memset(color,-1,sizeof(color)); if( !dfs(u,0) ) { can[u] = true; while(cc--)can[tmp[cc]]=true; } } } else if(Instack[v] && Low[u] > DFN[v]) Low[u] = DFN[v]; } } void solve(int n) { memset(DFN,0,sizeof DFN); memset(Instack,false,sizeof Instack); Index = block = top = 0; memset(can,false,sizeof can); for(int i = 1;i <= n;i++) if(!DFN[i]) Tarjan(i,-1); int ans = n; for(int i = 1;i <= n;i++) if(can[i]) ans--; printf("%d\n",ans); } void init() { tot = 0; memset(head,-1,sizeof head); } int g[N][N]; int main() { int n,m,u,v; while(scanf("%d%d",&n,&m),n) { init(); memset(g,0,sizeof g); while(m--) { scanf("%d%d",&u,&v); g[u][v]=g[v][u]=1; } for(int i = 1;i <= n;i++) for(int j = 1;j <= n;j++) if(i != j && g[i][j]==0) addedge(i,j); solve(n); } return 0; }
┆凉┆暖┆降┆等┆幸┆我┆我┆里┆将┆ ┆可┆有┆谦┆戮┆那┆ ┆大┆始┆ ┆然┆
┆薄┆一┆临┆你┆的┆还┆没┆ ┆来┆ ┆是┆来┆逊┆没┆些┆ ┆雁┆终┆ ┆而┆
┆ ┆暖┆ ┆如┆地┆站┆有┆ ┆也┆ ┆我┆ ┆的┆有┆精┆ ┆也┆没┆ ┆你┆
┆ ┆这┆ ┆试┆方┆在┆逃┆ ┆会┆ ┆在┆ ┆清┆来┆准┆ ┆没┆有┆ ┆没┆
┆ ┆生┆ ┆探┆ ┆最┆避┆ ┆在┆ ┆这┆ ┆晨┆ ┆的┆ ┆有┆来┆ ┆有┆
┆ ┆之┆ ┆般┆ ┆不┆ ┆ ┆这┆ ┆里┆ ┆没┆ ┆杀┆ ┆来┆ ┆ ┆来┆
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 智能桌面机器人:用.NET IoT库控制舵机并多方法播放表情
· Linux glibc自带哈希表的用例及性能测试
· 深入理解 Mybatis 分库分表执行原理
· 如何打造一个高并发系统?
· .NET Core GC压缩(compact_phase)底层原理浅谈
· DeepSeek火爆全网,官网宕机?本地部署一个随便玩「LLM探索」
· 开发者新选择:用DeepSeek实现Cursor级智能编程的免费方案
· 【译】.NET 升级助手现在支持升级到集中式包管理
· 独立开发经验谈:如何通过 Docker 让潜在客户快速体验你的系统
· Tinyfox 发生重大改版