~~~题面~~~

题解:

  考场上只想到了找点双,,,,然后不知道怎么处理奇环的问题。

  我们考虑对图取补集,这样两点之间连边就代表它们可以相邻, 那么一个点合法当且仅当有至少一个大小至少为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 ;
}

最新文章

  1. 使用JQuery统计input和textarea文字输入数量代码
  2. setWinldowRgn
  3. POJ 3666 Making the Grade
  4. thinkphp连接数据库
  5. Zabbix通过percona监控MySQL
  6. POJ 3301 Texas Trip (三分)
  7. yii2 rbac 设计
  8. Java集合源码分析
  9. DATEDIFF()(转)
  10. Javascript Promise 学习(上)
  11. Directx11学习笔记【七】 游戏定时器的实现
  12. USB硬盘 raw之后,DiskGenius 恢复
  13. java实现——008旋转数组的最小数字
  14. 【原创】bootstrap框架的学习 第五课
  15. 前端面试题(6)图片格式jpg,gif,png-8,png-24的区别,及其各自的使用场景
  16. Python 终端输出字体颜色
  17. 怎样使用C# MD5加密来增强密码的安全度
  18. 设计模式C++学习笔记之十二(Command命令模式)
  19. CareerCup All in One 题目汇总
  20. extjs如何使用

热门文章

  1. cakephp2.x 多个应用程序公用一个核心类库
  2. 代码混淆防止APP被反编译指南
  3. create-react-app react-redux项目 配置模块热更新hmr
  4. 怎么设计好移动APP测试用例
  5. 【JAVA】关于java中 类.class.getResource(&quot;/&quot;).getPath()获取路径有空格的问题
  6. 第六模块:WEB框架开发 第1章&#183;Django框架开发1~50
  7. 【第一章】MySQL数据概述
  8. 如何在线测试Exchange的速度
  9. kosaraju求强连通分量
  10. Python3 下安装python-votesmart