uvalive 3523 Knights of the Round Table 圆桌骑士(强连通+二分图)
题目真心分析不出来。看了白书才明白,不过有点绕脑。
容易想到,把题目给的不相邻的关系,利用矩阵,反过来建图。既然是全部可行的关系,那么就应该能画出含奇数个点的环。求环即是求双连通分量:找出所有的双连通分量,只要分量中的点数是奇数,则排除“must be expelled”的可能性。
判环上的点数用二分图,这个我都想了半天= =,如果是奇数个点,明摆着多出来的一个点放到哪个集合都会与集合内的点连边(这个找三个点自己画画试试就明白了)。0、1染色,本人喜欢用bfs,递归什么的其实都可以。
我自己用缩点做的,果断wa到吐。举个例子:五个点,{1,2,3}{3,4,5},这样3就是一个割顶了,缩点的话是在遍历完邻接表之后,再判断low[u]==dfn[u],如此5个点就缩成了一个点,即一个分量,虽然这个分量包含奇数个点,输出同样是0,但与我们的思路是不一样的。实际情况是分成两个分量,每个分量有三个点,割顶3同时出现在两个分量中。然后想着改进,当把割顶弹出栈后,再弹入,搞啊搞,还是算了,学着白书上用边搞。
#include<stdio.h>
#include<string.h>
#include<vector>
#include<stack>
#include<algorithm>
using namespace std; const int MAXN=; struct EDGE{
int u,v;
EDGE(){}
EDGE(int _u,int _v):u(_u),v(_v){}
}; struct Edge{
int v,next;
Edge(){}
Edge(int _v,int _next):v(_v),next(_next){}
}edge[MAXN*MAXN]; int mp[MAXN][MAXN],tol,head[MAXN];
int low[MAXN],dfn[MAXN],bccno[MAXN],iscut[MAXN],TT,bcc_cnt;
int que[MAXN],color[MAXN];
int sign[MAXN]; vector<int >bcc[MAXN];
stack<EDGE >stk; void init()
{
tol=;
memset(head,-,sizeof(head));
} void add(int u,int v)
{
edge[tol]=Edge(v,head[u]);
head[u]=tol++;
} void dfs(int u,int fa)
{
low[u]=dfn[u]=++TT;
int son=;
for(int i=head[u];i!=-;i=edge[i].next)
{
int v=edge[i].v;
EDGE e=EDGE(u,v);
if(!dfn[v]){
stk.push(e);
son++;
dfs(v,u);
low[u]=min(low[v],low[u]);
if(low[v]>=low[u]){
iscut[u]=;
bcc_cnt++;
bcc[bcc_cnt].clear();
while()
{
EDGE x=stk.top();
stk.pop();
if(bccno[x.u]!=bcc_cnt){
bcc[bcc_cnt].push_back(x.u);
bccno[x.u]=bcc_cnt;
}
if(bccno[x.v]!=bcc_cnt){
bcc[bcc_cnt].push_back(x.v);
bccno[x.v]=bcc_cnt;
}
if(x.u==u&&x.v==v)
break;
}
}
}else if(dfn[v]<dfn[u]&&v!=fa){
stk.push(e);
low[u]=min(low[u],dfn[v]);
}
}
if(fa<&&son==)
iscut[u]=;
} void find_bcc(int n)
{
memset(low,,sizeof(low));
memset(dfn,,sizeof(dfn));
memset(bccno,,sizeof(bccno));
memset(iscut,,sizeof(iscut)); TT=bcc_cnt=; for(int i=;i<=n;i++)
if(!dfn[i])
dfs(i,-);
} bool bfs(int x,int fa)
{
int l,r;
l=r=;
que[r++]=x;
while(l<r)
{
int u=que[l++];
for(int i=head[u];i!=-;i=edge[i].next)
{
int v=edge[i].v;
if(bccno[v]!=fa)
continue ;
if(color[v]==-){
color[v]=color[u]^;
que[r++]=v;
}else if(color[v]==color[u])
return false;
}
}
return true;
} void Bjudge()
{
memset(sign,,sizeof(sign));
for(int i=;i<=bcc_cnt;i++)
{
memset(color,-,sizeof(color));
for(int j=;j<bcc[i].size();j++)
bccno[bcc[i][j]]=i;
int u=bcc[i][];
color[u]=;
if(!bfs(u,i)){
for(int j=;j<bcc[i].size();j++)
sign[bcc[i][j]]=;
}
}
} int main()
{
int n,m;
int a,b;
while(~scanf("%d%d",&n,&m)!=EOF)
{
if(!n&&!m)
break;
memset(mp,,sizeof(mp));
for(int i=;i<m;i++)
{
scanf("%d%d",&a,&b);
mp[a][b]=mp[b][a]=;
} init();
for(int i=;i<=n;i++)
{
for(int j=i+;j<=n;j++)
{
if(!mp[i][j]){
add(i,j);
add(j,i);
}
}
} find_bcc(n); Bjudge(); int ans=;
for(int i=;i<=n;i++)
if(!sign[i])
ans++;
printf("%d\n",ans);
}
return ;
}
/*
5 4
1 4
1 5
2 4
2 5 6 8
1 4 1 5 1 6
2 4 2 5 2 6
3 4 3 5
*/
最近做了几道connectivity的题目,总结一下。
关于割顶、桥、双连通、边双连通,以及强连通处理方式有其相似性,关键都与时间戳有关。
其中,割顶->双连通 是low[v]>=dfn[u],桥->边双连通 是low[v]>dfn[u],只是一个等号的差别,其他处理基本相同;而强连通总是伴随着缩点 low[u]==dfn[u](这个一般是做边标记edge[].vis,这样即使是无向图也可以以edge[i^1].vis标记掉,而不影响重边的情况)。事实上,如果不考虑具体的桥,对边-双连通分量的划分就是在做无向图上的缩点操作。
这三个判定条件的位置也有不同。缩点是在遍历完u的邻接表之后,用每个low[v]的值更新low[u],并且u本身不会连到祖先去(这一点很重要),则是一个环,可以缩掉;在无向图中,判断双连通分量,也就是割顶(边-双连通分量&桥 一样),是每遍历一个孩子v,就要判断:low[v]>=dfn[u],只要点u的孩子所能到达的最大值不超过u,那么u就是割顶(删除u后,该子树独立),当然,u的每一个孩子v都可以是被 割顶u 分离,注意u本身是可以与它的祖先连接的!!
uvalive 3523 Knights of the Round Table 圆桌骑士(强连通+二分图)的更多相关文章
- UVALive 3523 Knights of the Round Table 圆桌骑士 (无向图点双连通分量)
由于互相憎恨的骑士不能相邻,把可以相邻的骑士连上无向边,会议要求是奇数,问题就是求不在任意一个简单奇圈上的结点个数. 如果不是二分图,一定存在一个奇圈,同一个双连通分量中其它点一定可以加入奇圈.很明显 ...
- UVALive - 3523 - Knights of the Round Table
Problem UVALive - 3523 - Knights of the Round Table Time Limit: 4500 mSec Problem Description Input ...
- POJ2942 UVA1364 Knights of the Round Table 圆桌骑士
POJ2942 洛谷UVA1364(博主没有翻墙uva实在是太慢了) 以骑士为结点建立无向图,两个骑士间存在边表示两个骑士可以相邻(用邻接矩阵存图,初始化全为1,读入一对憎恨关系就删去一条边即可),则 ...
- poj 2942 Knights of the Round Table 圆桌骑士(双连通分量模板题)
Knights of the Round Table Time Limit: 7000MS Memory Limit: 65536K Total Submissions: 9169 Accep ...
- UVALive 3523 : Knights of the Round Table (二分图+BCC)
题目链接 题意及题解参见lrj训练指南 #include<bits/stdc++.h> using namespace std; ; int n,m; int dfn[maxn],low[ ...
- KNIGHTS - Knights of the Round Table 圆桌骑士 点双 + 二分图判定
---题面--- 题解: 考场上只想到了找点双,,,,然后不知道怎么处理奇环的问题. 我们考虑对图取补集,这样两点之间连边就代表它们可以相邻, 那么一个点合法当且仅当有至少一个大小至少为3的奇环经过了 ...
- POJ2942 Knights of the Round Table[点双连通分量|二分图染色|补图]
Knights of the Round Table Time Limit: 7000MS Memory Limit: 65536K Total Submissions: 12439 Acce ...
- uva 3523 Knights of the Round Table
题意:给你n,m n为有多少人,m为有多少组关系,每组关系代表两人相互憎恨,问有多少个骑士不能参加任何一个会议. 白书算法指南 对于每个双联通分量,若不是二分图,就把里面的节点标记 #include ...
- UVALive-3523 Knights of the Round Table (双连通分量+二分图匹配)
题目大意:有n个骑士要在圆桌上开会,但是相互憎恶的两个骑士不能相邻,现在已知骑士们之间的憎恶关系,问有几个骑士一定不能参加会议.参会骑士至少有3个且有奇数个. 题目分析:在可以相邻的骑士之间连一条无向 ...
随机推荐
- Spring+Mybatis+Maven 整合配置
<?xml version="1.0" encoding="UTF-8"?> <beans default-autowire="by ...
- iOS开发之深入探讨runtime机制02-runtime的简单使用
runtime机制为我们提供了一系列的方法让我们可以在程序运行时动态修改类.对象中的所有属性.方法. 下面就介绍运行时一种很常见的使用方式,字典转模型.当然,你可能会说,“我用KVO直接 setVal ...
- C# 虚方法 与 隐藏方法(new) 区别
重写和隐藏的定义: 重写:继承时发生,在子类中重新定义父类中的方法,子类中的方法和父类的方法是一样的 例如:基类方法声明为virtual(虚方法),派生类中使用override申明此 ...
- java调用dll文件中的类型转换
char *转String (env)->NewStringUTF("the content you want to type in"); char *转jbyteArr ...
- C#中sealed关键字
C#中sealed关键字 1. sealed关键字 当对一个类应用 sealed 修饰符时,此修饰符会阻止其他类从该类继承.类似于Java中final关键字. 在下面的示例中,类 B ...
- hdu 2736 Surprising Strings(类似哈希,字符串处理)
重点在判重的方法,嘻嘻 题目 #define _CRT_SECURE_NO_WARNINGS #include<stdio.h> #include<string.h> int ...
- Linux解压 tar命令
tar [-cxtzjvfpPN] 文件与目录 ....参数:-c :建立一个压缩文件的参数指令(create 的意思):-x :解开一个压缩文件的参数指令!-t :查看 tarfile 里面的文件! ...
- lintcode :链表插入排序
题目: 链表插入排序 用插入排序对链表排序 样例 Given 1->3->2->0->null, return 0->1->2->3->null 解题: ...
- Linux中断处理体系结构分析
Linux中断处理体系结构分析(一) 异常,就是可以打断CPU正常运行流程的一些事情,比如外部中断.未定义指令.试图修改只读的数据.执行swi指令(Software Interrupt Instruc ...
- Linux内核的同步机制
本文详细的介绍了Linux内核中的同步机制:原子操作.信号量.读写信号量和自旋锁的API,使用要求以及一些典型示例 一.引言 在现代操作系统里,同一时间可能有多个内核执行流在执行,因此内核其实象多进程 ...