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同时出现在两个分量中。然后想着改进,当把割顶弹出栈后,再弹入,搞啊搞,还是算了,学着白书上用边搞。
1 #include<stdio.h> 2 #include<string.h> 3 #include<vector> 4 #include<stack> 5 #include<algorithm> 6 using namespace std; 7 8 const int MAXN=1111; 9 10 struct EDGE{ 11 int u,v; 12 EDGE(){} 13 EDGE(int _u,int _v):u(_u),v(_v){} 14 }; 15 16 struct Edge{ 17 int v,next; 18 Edge(){} 19 Edge(int _v,int _next):v(_v),next(_next){} 20 }edge[MAXN*MAXN]; 21 22 int mp[MAXN][MAXN],tol,head[MAXN]; 23 int low[MAXN],dfn[MAXN],bccno[MAXN],iscut[MAXN],TT,bcc_cnt; 24 int que[MAXN],color[MAXN]; 25 int sign[MAXN]; 26 27 vector<int >bcc[MAXN]; 28 stack<EDGE >stk; 29 30 void init() 31 { 32 tol=0; 33 memset(head,-1,sizeof(head)); 34 } 35 36 void add(int u,int v) 37 { 38 edge[tol]=Edge(v,head[u]); 39 head[u]=tol++; 40 } 41 42 void dfs(int u,int fa) 43 { 44 low[u]=dfn[u]=++TT; 45 int son=0; 46 for(int i=head[u];i!=-1;i=edge[i].next) 47 { 48 int v=edge[i].v; 49 EDGE e=EDGE(u,v); 50 if(!dfn[v]){ 51 stk.push(e); 52 son++; 53 dfs(v,u); 54 low[u]=min(low[v],low[u]); 55 if(low[v]>=low[u]){ 56 iscut[u]=1; 57 bcc_cnt++; 58 bcc[bcc_cnt].clear(); 59 while(1) 60 { 61 EDGE x=stk.top(); 62 stk.pop(); 63 if(bccno[x.u]!=bcc_cnt){ 64 bcc[bcc_cnt].push_back(x.u); 65 bccno[x.u]=bcc_cnt; 66 } 67 if(bccno[x.v]!=bcc_cnt){ 68 bcc[bcc_cnt].push_back(x.v); 69 bccno[x.v]=bcc_cnt; 70 } 71 if(x.u==u&&x.v==v) 72 break; 73 } 74 } 75 }else if(dfn[v]<dfn[u]&&v!=fa){ 76 stk.push(e); 77 low[u]=min(low[u],dfn[v]); 78 } 79 } 80 if(fa<0&&son==1) 81 iscut[u]=0; 82 } 83 84 void find_bcc(int n) 85 { 86 memset(low,0,sizeof(low)); 87 memset(dfn,0,sizeof(dfn)); 88 memset(bccno,0,sizeof(bccno)); 89 memset(iscut,0,sizeof(iscut)); 90 91 TT=bcc_cnt=0; 92 93 for(int i=1;i<=n;i++) 94 if(!dfn[i]) 95 dfs(i,-1); 96 } 97 98 bool bfs(int x,int fa) 99 { 100 int l,r; 101 l=r=0; 102 que[r++]=x; 103 while(l<r) 104 { 105 int u=que[l++]; 106 for(int i=head[u];i!=-1;i=edge[i].next) 107 { 108 int v=edge[i].v; 109 if(bccno[v]!=fa) 110 continue ; 111 if(color[v]==-1){ 112 color[v]=color[u]^1; 113 que[r++]=v; 114 }else if(color[v]==color[u]) 115 return false; 116 } 117 } 118 return true; 119 } 120 121 void Bjudge() 122 { 123 memset(sign,0,sizeof(sign)); 124 for(int i=1;i<=bcc_cnt;i++) 125 { 126 memset(color,-1,sizeof(color)); 127 for(int j=0;j<bcc[i].size();j++) 128 bccno[bcc[i][j]]=i; 129 int u=bcc[i][0]; 130 color[u]=0; 131 if(!bfs(u,i)){ 132 for(int j=0;j<bcc[i].size();j++) 133 sign[bcc[i][j]]=1; 134 } 135 } 136 } 137 138 int main() 139 { 140 int n,m; 141 int a,b; 142 while(~scanf("%d%d",&n,&m)!=EOF) 143 { 144 if(!n&&!m) 145 break; 146 memset(mp,0,sizeof(mp)); 147 for(int i=0;i<m;i++) 148 { 149 scanf("%d%d",&a,&b); 150 mp[a][b]=mp[b][a]=1; 151 } 152 153 init(); 154 for(int i=1;i<=n;i++) 155 { 156 for(int j=i+1;j<=n;j++) 157 { 158 if(!mp[i][j]){ 159 add(i,j); 160 add(j,i); 161 } 162 } 163 } 164 165 find_bcc(n); 166 167 Bjudge(); 168 169 int ans=0; 170 for(int i=1;i<=n;i++) 171 if(!sign[i]) 172 ans++; 173 printf("%d\n",ans); 174 } 175 return 0; 176 } 177 /* 178 5 4 179 1 4 180 1 5 181 2 4 182 2 5 183 184 6 8 185 1 4 1 5 1 6 186 2 4 2 5 2 6 187 3 4 3 5 188 */
View Code
最近做了几道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本身是可以与它的祖先连接的!!
转载于:https://www.cnblogs.com/zstu-abc/p/3234037.html
uvalive 3523 Knights of the Round Table 圆桌骑士(强连通+二分图)相关推荐
- Uvalive 3523 - Knights of the Round Table (双连通分量+二分图)
题目链接 https://vjudge.net/problem/UVALive-3523 [题意] 有n个骑士经常举行圆桌会议,每次圆桌会议应至少有3个人参加且人数必须是奇数,相互憎恨的骑士不能坐在圆 ...
- POJ2942 UVA1364 Knights of the Round Table 圆桌骑士
POJ2942 洛谷UVA1364(博主没有翻墙uva实在是太慢了) 以骑士为结点建立无向图,两个骑士间存在边表示两个骑士可以相邻(用邻接矩阵存图,初始化全为1,读入一对憎恨关系就删去一条边即可),则 ...
- poj 2942 Knights of the Round Table(双连通分量+tarjan+二分图判定)
http://poj.org/problem?id=2942 题意: 有N个骑士,给出某些骑士之间的仇恨关系,骑士们开会时会围坐在一个圆桌旁.一次会议能够顺利举行,要满足两个条件: 1:任意相互憎恨的 ...
- POJ2942 Knights of the Round Table 点双连通分量 二分图判定
题目大意 有N个骑士,给出某些骑士之间的仇恨关系,每次开会时会选一些骑士开,骑士们会围坐在一个圆桌旁.一次会议能够顺利举行,要满足两个条件:1.任意相互憎恨的两个骑士不能相邻.2.开会人数为大于2的奇 ...
- POJ 2942 Knights of the Round Table ★(点双连通分量+二分图判定)
题意:找出图中不可能在奇圈中的点. [分析]注意到,在不同点双连通分量中的两个点,显然是不会存在圈的.那么这样,问题就划归为在点双连通分量中去找奇圈. [重要性质]在一个点双连通分量中,只要有任意一个 ...
- 如果圆桌骑士有特殊情况(Knights of the Round Table)
题目描述 Being a knight is a very attractive career: searching for the Holy Grail, saving damsels in dis ...
- UVA1364 Knights of the Round Table(双连通分量、二分图染色,超详细解释)
整理的算法模板合集: ACM模板 UVA1364 Knights of the Round Table 题目中要求互相有憎恨关系的人不能坐在相邻的位置,一个圆桌可以很形象地看作是一个环,也就是说我们两 ...
- 【POJ - 2942】Knights of the Round Table(点双连通分量,二分图判断奇环奇圈)
题干: Being a knight is a very attractive career: searching for the Holy Grail, saving damsels in dist ...
- CRI Round Table圆桌议事-极力推荐提升英语听力口语的必备播客
CRI Round Table,别名EZFM Round Table或者Round Table圆桌会议,其实都是同一个Round Table,被称之为英文版"锵锵三人行",是观点自 ...
最新文章
- Hibernate 所有缓存机制详解
- php yield 导出文件,PHP yield 读取大文件
- 没有流程的项目管理,都是无用功!
- 【NOIP模拟】方格稿纸
- 利用dft的定义计算dft的matlab程序_CP2K教程系列之静态计算(Pymatflow篇)
- 八皇后解法(回溯法)
- 【前端 · 面试 】HTTP 总结(九)—— HTTP 协商缓存
- Android LED电子表时钟字体digital font
- 电子基础大全:整理了电子设计所需的基础知识
- PFC颗粒6.0软件模拟---工程案例
- vim打开文件时显示行号
- 透视相机怎么得到正交效果
- 如何申请微信号测试账号,进行微信开发
- 蓝天保卫战之产品测试服务
- uniapp+canvas实现app在线电子签名
- ggplot2 theme主题参数详解
- 数据结构课程设计-推箱子
- Go 内存管理与垃圾回收
- 网易163企业邮箱注册申请,有什么优惠活动
- 程序人生:平民百姓中的这些“二代”究竟有多难