http://poj.org/problem?id=2942

所写的tarjan练习题最难的一道。

说白了难在考得不是纯tarjan。

首先我们把仇恨关系处理成非仇恨关系的图,然后找双连通分量,在双连通分量里的点满足了任意一个人可以和两个(或以上)的人坐一起。

那么我们接下来要判断奇环。

发现性质:如果一个双连通分量有奇环,那么其中任意一点一定在某个奇环上。

也就是说,这些人拼一拼绝对能全部开会成功,我们把他们打上成功标志。

然后搜失败标志的人的个数即可。

判断奇环的方法显然二分图染色。

#include<stack>
#include<cstdio>
#include<cstring>
#include<vector>
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long ll;
inline int read(){
int x=,w=;char ch=;
while(ch<''||ch>''){if(ch=='-')w=-;ch=getchar();}
while(ch>=''&&ch<=''){x=(x<<)+(x<<)+ch-'';ch=getchar();}
return x*w;
}
const int maxn=;
struct node{
int st;
int to;
int nxt;
}edge[];
int cnt,head[maxn];
void add(int u,int v){
cnt++;
edge[cnt].st=u;
edge[cnt].to=v;
edge[cnt].nxt=head[u];
head[u]=cnt;
return;
}
bool dis[maxn][maxn];
bool ok[maxn];
int color[maxn];
int dfn[maxn];
int low[maxn];
bool inslt[maxn];
int t=;
int n,m;
int numslt[maxn];
stack<int>q;
vector<int>slt[maxn];
int slt_cnt;
void tarjan(int u,int f){
t++;
dfn[u]=t;
low[u]=t;
for(int i=head[u];i;i=edge[i].nxt){
int v=edge[i].to;
if(!dfn[v]){
q.push(i);
tarjan(v,u);
low[u]=min(low[u],low[v]);
if(low[v]>=dfn[u]){
slt_cnt++;
slt[slt_cnt].clear();
while(){
int num=q.top();
q.pop();
if(numslt[edge[num].st]!=slt_cnt){
numslt[edge[num].st]=slt_cnt;
slt[slt_cnt].push_back(edge[num].st);
}
if(numslt[edge[num].to]!=slt_cnt){
numslt[edge[num].to]=slt_cnt;
slt[slt_cnt].push_back(edge[num].to);
}
if(edge[num].to==v&&edge[num].st==u)break;
}
}
}else if(f!=v){
if(low[u]>dfn[v]){
q.push(i);
low[u]=dfn[v];
}
}
}
return;
}
bool draw(int u){
bool ret=;
for(int i=head[u];i;i=edge[i].nxt){
int v=edge[i].to;
if(!inslt[v])continue;
if(color[v]==-){
color[v]=-color[u];
ret|=draw(v);
}else if(color[v]==color[u]){
return ;
}
}
return ret;
}
void clr(){
cnt=;slt_cnt=;
while(!q.empty())q.pop();
memset(dfn,,sizeof(dfn));
memset(low,,sizeof(low));
memset(numslt,,sizeof(numslt));
memset(head,,sizeof(head));
memset(dis,,sizeof(dis));
memset(ok,,sizeof(ok));
return;
}
int main(){
n=read();
m=read();
while(n||m){
clr();
for(int i=;i<=m;i++){
int u=read();
int v=read();
dis[u][v]=dis[v][u]=;
}
for(int i=;i<=n;i++){
for(int j=i+;j<=n;j++){
if(!dis[i][j]){
add(i,j);
add(j,i);
}
}
}
for(int i=;i<=n;i++){
if(!dfn[i]){
tarjan(i,);
}
}
for(int i=;i<=slt_cnt;i++){
memset(inslt,,sizeof(inslt));
memset(color,-,sizeof(color));
int u;
for(int j=;j<slt[i].size();j++){
u=slt[i][j];
inslt[u]=;
}
color[u]=;
if(draw(u)){
for(int j=;j<slt[i].size();j++){
u=slt[i][j];
ok[u]=;
}
}
}
int ans=;
for(int i=;i<=n;i++)if(!ok[i])ans++;
printf("%d\n",ans);
n=read();m=read();
}
return ;
}

最新文章

  1. 有一个团队协同工具,叫Worktile
  2. Windows Azure Virtual Machine 之用程序控制Azure VM
  3. 从为什么String=String谈到StringBuilder和StringBuffer
  4. [荐]使用Js操作注册表
  5. jq 操作radio,设置选中、获取选中值
  6. Linux 下的另一个密码破解工具medusa
  7. Combination Sum | &amp; || &amp; ||| &amp; IV
  8. cookiecutter-flask生成的框架里边自带了一个CRUDMixin类
  9. 利用mycat实现mysql数据库读写分离
  10. 给内置对象或自定义对象添加存取器属性(getter setter)的方法总结
  11. T-SQL问题解决集锦——数据加解密
  12. HTML添加样式三种办法
  13. Boto3
  14. abp 设置默认语言为中文
  15. [转]用virtualBox安装centos设置网络和通信
  16. 元注解——java.lang.annotation.Target(1.8)
  17. 关于java做题时需要注意的事项
  18. Eclipse 保存文件时自动格式化代码
  19. E437: terminal capability &quot;cm&quot; required 错误出现的原因和解决方法
  20. Oracle体系结构之Oracle基本数据字典:v$database、v$instance、v$version、dba_objects

热门文章

  1. KubeCon深度洞察 | KubeEdge开源首秀
  2. python3读取csv文件
  3. python基础之变量和简单数据类型
  4. Javascript打印网页局部的实现方案
  5. Linux命令应用大词典-第41章 MySQL数据库
  6. Unity Lighting - Choosing a Rendering Path 选择渲染路径(三)
  7. (C#)工厂方法模式
  8. Codeforces-A. Shortest path of the king(简单bfs记录路径)
  9. ionic ios样式偏移解决方案。
  10. CPU设计学习-流水线