【图论 搜索】bzoj1064: [Noi2008]假面舞会
做到最后发现还是读题比赛;不过还是很好的图论题的
Description
一年一度的假面舞会又开始了,栋栋也兴致勃勃的参加了今年的舞会。今年的面具都是主办方特别定制的。每个参加舞会的人都可以在入场时选择一 个自己喜欢的面具。每个面具都有一个编号,主办方会把此编号告诉拿该面具的人。为了使舞会更有神秘感,主办方把面具分为k (k≥3)类,并使用特殊的技术将每个面具的编号标在了面具上,只有戴第i 类面具的人才能看到戴第i+1 类面具的人的编号,戴第k 类面具的人能看到戴第1 类面具的人的编号。 参加舞会的人并不知道有多少类面具,但是栋栋对此却特别好奇,他想自己算出有多少类面具,于是他开始在人群中收集信息。 栋栋收集的信息都是戴第几号面具的人看到了第几号面具的编号。如戴第2号面具的人看到了第5 号面具的编号。栋栋自己也会看到一些编号,他也会根据自己的面具编号把信息补充进去。由于并不是每个人都能记住自己所看到的全部编号,因此,栋栋收集的信 息不能保证其完整性。现在请你计算,按照栋栋目前得到的信息,至多和至少有多少类面具。由于主办方已经声明了k≥3,所以你必须将这条信息也考虑进去。
Input
第一行包含两个整数n, m,用一个空格分隔,n 表示主办方总共准备了多少个面具,m 表示栋栋收集了多少条信息。接下来m 行,每行为两个用空格分开的整数a, b,表示戴第a 号面具的人看到了第b 号面具的编号。相同的数对a, b 在输入文件中可能出现多次。
Output
包含两个数,第一个数为最大可能的面具类数,第二个数为最小可能的面具类数。如果无法将所有的面具分为至少3 类,使得这些信息都满足,则认为栋栋收集的信息有错误,输出两个-1。
Sample Input
6 5
1 2
2 3
3 4
4 1
3 5
【输入样例二】
3 3
1 2
2 1
2 3
Sample Output
4 4
【输出样例二】
-1 -1
HINT
100%的数据,满足n ≤ 100000, m ≤ 1000000。
题目分析
naive
首先会有一个很naive的想法:
对于无环的图找最大值:拓扑地从1开始标号dfs做下去,中途检查边$(u,v)$,若$v$已经被标号且$col_v≠col_u+1$,就是不合法的,随即输出"-1 -1"。

讲上去求的是最大值所以看上去很对劲是吧?

但是遇上这么一个环呢?7之后连的是2,所以判成无解。但是然而实际上$k=3$是成立的。
也就是说,简单地考虑“环缩点”或者“直接染色”是行不通的。
实际做法
学了tarjan之后不要在找环只想到tarjan!
这个问题其实建个反向边之后,可以分为两类:
- 有环的
- 没环的
没环的情况:树是很简单的,最大值就是所有树的最长链总和,最小值一定是3。
有环的情况:
DFS听上去很基础吧,但是切不要以为基础的东西就没什么用处。
这里依靠DFS找出每一个环的长度,并且注意到最大答案就是所有环长度的gcd。只要最终的$gcd≥3$,结合没环情况的下界可知环外其他树对答案不造成影响。
可能会想到环套环的情况。不过首先这个DFS要永久标记访问,复杂度是$O(n)$的,不会被卡;其次我们求的是环长度的gcd,并且如果答案合法,大环长度一定是小环的倍数,所以即便大环套在小环外,也不影响最终答案。
大致思路就是这样。
细节注意树的情况,最大值是所有树的最长链总和!
#include<bits/stdc++.h>
const int maxn = ;
const int maxm = ; struct node
{
int id;
std::vector<int> norEdge,difEdge;
}a[maxn];
int n,m,cnt,mn,mx,chain,ans;
bool vis[maxn];
std::pair<int, int> edges[maxm]; int read()
{
char ch = getchar();
int num = ;
bool fl = ;
for (; !isdigit(ch); ch = getchar())
if (ch=='-') fl = ;
for (; isdigit(ch); ch = getchar())
num = (num<<)+(num<<)+ch-;
if (fl) num = -num;
return num;
}
int gcd(int x, int y){return !y?x:gcd(y, x%y);}
void addedge(int x)
{
int u = edges[x].first, v = edges[x].second;
a[u].norEdge.push_back(v), a[v].difEdge.push_back(u);
}
void dfs(int x, int lb)
{
if (vis[x]){
ans = gcd(ans, abs(a[x].id-lb)); //找到一个环了
return;
}
a[x].id = lb, vis[x] = ;
mn = std::min(mn, lb), mx = std::max(mx, lb);
int sa = a[x].norEdge.size(), sb = a[x].difEdge.size();
for (int i=; i<sa; i++)
dfs(a[x].norEdge[i], lb+); //正向边
for (int i=; i<sb; i++)
dfs(a[x].difEdge[i], lb-); //反向边
return;
}
int main()
{
// freopen("testdata.in","r",stdin);
n = read(), m = read();
for (int i=; i<=m; i++)
edges[i].first = read(), edges[i].second = read();
std::sort(edges+, edges+m+); //用pair存边方便去重
addedge();
for (int i=; i<=m; i++)
if (edges[i]!=edges[i-])
addedge(i);
for (int i=; i<=n; i++)
if (!vis[i]){ //由于建了双向边,故不用考虑拓扑序
dfs(i, );
chain += mx-mn+;
mn = mx = ;
}
if (ans >= ){ //如果有环并且合法
for (int i=; i<=ans/; i++)
if (ans%i==){
printf("%d %d\n",ans,i); //找最小的答案——求最小约数
return ;
}
printf("%d %d\n",ans,ans); //最小答案还是ans
return ;
}
if (!ans&&chain>=){
printf("%d %d\n",chain,);
return ;
} //否则不合法,ans=1
printf("-1 -1\n");
return ;
}
END
【图论 搜索】bzoj1064: [Noi2008]假面舞会的更多相关文章
- [BZOJ1064][Noi2008]假面舞会
[BZOJ1064][Noi2008]假面舞会 试题描述 一年一度的假面舞会又开始了,栋栋也兴致勃勃的参加了今年的舞会.今年的面具都是主办方特别定制的.每个参加舞会的人都可以在入场时选择一 个自己喜欢 ...
- BZOJ1064 [Noi2008]假面舞会 【dfs】
题目 一年一度的假面舞会又开始了,栋栋也兴致勃勃的参加了今年的舞会.今年的面具都是主办方特别定制的.每个参加舞会的人都可以在入场时选择一 个自己喜欢的面具.每个面具都有一个编号,主办方会把此编号告诉拿 ...
- BZOJ1064 NOI2008 假面舞会 图论
传送门 将一组关系\((A,B)\)之间连一条边,那么显然如果图中存在环长为\(len\)的环,那么面具的种数一定是\(len\)的因数. 值得注意的是这里环的关系除了\(A \rightarrow ...
- BZOJ1064 NOI2008假面舞会(dfs树)
将图中的环的长度定义为正向边数量-反向边数量,那么答案一定是所有环的环长的共同因子.dfs一下就能找到图中的一些环,并且图中的所有环的环长都可以由这些环长加加减减得到(好像不太会证).如果有环长为1或 ...
- BZOJ1064 NOI2008假面舞会
挺神的这题,发现只有环和链两种情况 搜索时我们只考虑环的,因为链可以看成找不到分类的环. 当成链时大小是的最大值是各链长的和,最小值是3 当成环时最大值是各环长的gcd,最小值是大于3的最小的ans的 ...
- 【BZOJ1064】[Noi2008]假面舞会 DFS树
[BZOJ1064][Noi2008]假面舞会 Description 一年一度的假面舞会又开始了,栋栋也兴致勃勃的参加了今年的舞会.今年的面具都是主办方特别定制的.每个参加舞会的人都可以在入场时选择 ...
- 图论 公约数 找环和链 BZOJ [NOI2008 假面舞会]
BZOJ 1064: [Noi2008]假面舞会 Time Limit: 10 Sec Memory Limit: 162 MBSubmit: 1655 Solved: 798[Submit][S ...
- 【洛谷】1477:[NOI2008]假面舞会【图论】
P1477 [NOI2008]假面舞会 题目描述 一年一度的假面舞会又开始了,栋栋也兴致勃勃的参加了今年的舞会. 今年的面具都是主办方特别定制的.每个参加舞会的人都可以在入场时选择一 个自己喜欢的面具 ...
- NOI2008假面舞会
1064: [Noi2008]假面舞会 Time Limit: 10 Sec Memory Limit: 162 MBSubmit: 883 Solved: 462[Submit][Status] ...
随机推荐
- 怎么解决UIScrollView把uitableviewcell的点击事件屏蔽了
[self.contentView addSubview:self.scrollView]; self.scrollView.userInteractionEnabled = NO; [self.co ...
- Other Linker Flags里加上所需的参数
在Other Linker Flags里加上所需的参数,用到的参数一般有以下3个: -ObjC -all_load -force_load 下面来说说每个参数存在的意义和具体做的事情. 首先是-Obj ...
- [題解](縮點)luogu_P2341受歡迎的牛
對於每個強聯通分量,這些牛一定都互相喜歡,所以縮點(我也不知道怎麼想到的) 接下來就是統計答案,最後縮成了一個DAG圖,如果這個點是明星的話,其他每個點一定直接或間接的鏈接這個點 也就是說其他點一定有 ...
- 540 Single Element in a Sorted Array 有序数组中的单一元素
给定一个只包含整数的有序数组,每个元素都会出现两次,唯有一个数只会出现一次,找出这个数.示例 1:输入: [1,1,2,3,3,4,4,8,8]输出: 2 示例 2:输入: [3,3,7,7,10,1 ...
- 牛客网Java刷题知识点之方法覆盖(方法重写)和方法重载的区别
不多说,直接上干货! https://www.nowcoder.com/ta/review-java/review?query=&asc=true&order=&page=6 ...
- Unity Shader入门精要学习笔记 - 第11章 让画面动起来
转自 冯乐乐的 <Unity Shader入门精要> Unity Shader 中的内置变量 动画效果往往都是把时间添加到一些变量的计算中,以便在时间变化时画面也可以随之变化.Unity ...
- FTP上传下载 C#辅助类
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.N ...
- [转]AngularJS Cookies Example
AngularJS Cookies Example AngularJS 提供了很好的 $cookie 和 $cookieStore API 用来处理 cookies . 这两个服务都能够很好的发挥HT ...
- linux安装redis官方教程
官方链接:http://redis.io/download Download, extract and compile Redis with: $ wget http://download.redis ...
- CF1025B Weakened Common Divisor
思路: 首先选取任意一对数(a, b),分别将a,b进行因子分解得到两个因子集合然后取并集(无需计算所有可能的因子,只需得到不同的质因子即可),之后再暴力一一枚举该集合中的元素是否满足条件. 时间复杂 ...