KNIGHTS - Knights of the Round Table 圆桌骑士 点双 + 二分图判定
2024-10-15 19:07:22
题解:
考场上只想到了找点双,,,,然后不知道怎么处理奇环的问题。
我们考虑对图取补集,这样两点之间连边就代表它们可以相邻, 那么一个点合法当且仅当有至少一个大小至少为3的奇环经过了它。
观察到只会出现一棵类似树的结构 + t个相对独立的环, 因为环肯定都是独立出来的,所以可以不用管它。
因此我们先找出所有点双,然后判断这个点双内是否有奇环,用二分图染色来判断。如果有奇环,则说明这个点双内的所有点都可以出现在一个奇环上,反之则都不会出现。
所以我们只需要寻找一下点双,然后判断是否合法并加上相应贡献即可。
#include<bits/stdc++.h>
using namespace std;
#define R register int
#define AC 1100
#define ac 11000000 int n, m, cnt, timer, ans;
int q[AC], top;
int q1[AC], head, tail;
int belong[AC], low[AC], color[AC], dfn[AC];
bool z[AC][AC], vis[AC]; inline int read()
{
int x = ;char c = getchar();
while(c > '' || c < '') c = getchar();
while(c >= '' && c <= '') x = x * + c - '', c = getchar();
return x;
} void pre()
{
n = read(), m = read();
if(!n && !m) exit();
memset(belong, , sizeof(belong));
memset(vis, , sizeof(vis));
memset(dfn, , sizeof(dfn));
timer = cnt = ans = top = ;
memset(z, , sizeof(z));
int a, b;
for(R i = ; i <= m; i ++)
{
a = read(), b = read();
z[a][b] = z[b][a] = true;
}
for(R i = ; i <= n; i ++) z[i][i] = true;//不能走自环
} inline void upmin(int &a, int b){
if(b < a) a = b;
} bool check(int x)//检查x所在点双是否是一个二分图
{
memset(color, , sizeof(color));
head = tail = ;
q1[++tail] = x, color[x] = ;
while(head < tail)
{
x = q1[++head];
for(R i = ; i <= n; i ++)
{
if(!z[x][i] && belong[i] == cnt)//如果有边并且在同一个点双中
{
if(color[x] == color[i]) return false;
else if(!color[i]) q1[++tail] = i, color[i] = color[x] ^ ;
}
}
}
return true;
} void tarjan(int x, int fa)//求点双联通分量
{
low[x] = dfn[x] = ++ timer;
for(R i = ; i <= n; i ++)//枚举边
{
if(!z[x][i])
{
if(!dfn[i])
{
q[++top] = i;//将这个点加入栈
tarjan(i, x);
upmin(low[x], low[i]);
if(low[i] >= dfn[x])//这个点是割点
{
int tot = ;//先加上割点和当前now的tot
belong[x] = ++ cnt;//先给这个割点临时打上标记
while(q[top] != i) ++tot, belong[q[top --]] = cnt;//记录下这个点所属的点双联通分量
belong[q[top --]] = cnt;
if(!check(x))//不是二分图,那么这个bcc当中的点都是合法的
{
int b = top + tot - ;//直接把刚取出来的点打上标记
vis[x] = true;//q[top] 不一定是割点
for(R i = top + ; i <= b; i ++) vis[q[i]] = true;
}
}
}
else if(i != fa) upmin(low[x], dfn[i]);
}
}
} void work()
{
while()
{
pre();
for(R i = ; i <= n; i ++)
if(!dfn[i]) q[++top] = i, tarjan(i, i);//将当前点加入栈
for(R i = ; i <= n; i ++) if(!vis[i]) ++ans;
printf("%d\n", ans);
}
} int main()
{
// freopen("in.in", "r", stdin);
work();
// fclose(stdin);
return ;
}
最新文章
- 使用JQuery统计input和textarea文字输入数量代码
- setWinldowRgn
- POJ 3666 Making the Grade
- thinkphp连接数据库
- Zabbix通过percona监控MySQL
- POJ 3301 Texas Trip (三分)
- yii2 rbac 设计
- Java集合源码分析
- DATEDIFF()(转)
- Javascript Promise 学习(上)
- Directx11学习笔记【七】 游戏定时器的实现
- USB硬盘 raw之后,DiskGenius 恢复
- java实现——008旋转数组的最小数字
- 【原创】bootstrap框架的学习 第五课
- 前端面试题(6)图片格式jpg,gif,png-8,png-24的区别,及其各自的使用场景
- Python 终端输出字体颜色
- 怎样使用C# MD5加密来增强密码的安全度
- 设计模式C++学习笔记之十二(Command命令模式)
- CareerCup All in One 题目汇总
- extjs如何使用
热门文章
- cakephp2.x 多个应用程序公用一个核心类库
- 代码混淆防止APP被反编译指南
- create-react-app react-redux项目 配置模块热更新hmr
- 怎么设计好移动APP测试用例
- 【JAVA】关于java中 类.class.getResource(";/";).getPath()获取路径有空格的问题
- 第六模块:WEB框架开发 第1章&#183;Django框架开发1~50
- 【第一章】MySQL数据概述
- 如何在线测试Exchange的速度
- kosaraju求强连通分量
- Python3 下安装python-votesmart