一道非常神奇的图论题解法无比新奇清新

我们首先把图分成三种情况:

  1. 有环的,此时答案一定是环长的因数(否则不能满足题意)
  2. 存在入度大于1的DAG图的
  3. 一棵树/一条链

很容易发现,最后一种情况想怎么取就怎么取,那么我们只需要考虑1,2的影响即可

但是如果我们傻乎乎地直接跑好像也是可以的那就太烦了。

我们考虑这样的一个图:

我们把原图中的边分成两类:红色(顺时针)和绿色(逆时针)。然后我们发现这种图对应上面讲的情况2。然后手推颜色发现要两种。

而这个2是怎么来的,很简单,\(color=| total_{red}-total_{green} |\)。为什么,我们仔细观察一下对于每一个被一条顺时针边和一条逆时针边连接的点,与它相连的点颜色一定相同

然后我们就可以把问题转化成无向边并找环了。但是图中的边并没有顺时针/逆时针,于是我们分成正向边/反向边考虑即可。

可以设为相反的边权(如\(1 \&\& -1\)等)。然后取绝对值即可。

然后对于有环的情况(无论时1还是2),我们都可以得出\(ans=gcd(|len|)\),其中\(len\)表示环长,那么最小值就是\(min(ans|u)\)

值得注意的还有森林的情况,稍加推到此时的\(ans=\sum maxdis-mindis+1 \ (for\ each\ Unicom\ blocks\ of \ the\ gragh)\)

最后当得到的\(ans<3\)时无解。找环当然是BFS/DFS了(注意不要把SCC搞混了)

BFS版CODE

  1. #include<cstdio>
  2. #include<cctype>
  3. #include<cstring>
  4. using namespace std;
  5. const int N=100005,M=1000005;
  6. struct edge
  7. {
  8. int to,next,v;
  9. }e[M<<1];
  10. int head[N],dis[N],q[N],n,m,x,y,ans,lans,sum,cnt,MIN,MAX;
  11. bool vis[N];
  12. inline char tc(void)
  13. {
  14. static char fl[100000],*A=fl,*B=fl;
  15. return A==B&&(B=(A=fl)+fread(fl,1,100000,stdin),A==B)?EOF:*A++;
  16. }
  17. inline void read(int &x)
  18. {
  19. x=0; char ch; while (!isdigit(ch=tc()));
  20. while (x=(x<<3)+(x<<1)+ch-'0',isdigit(ch=tc()));
  21. }
  22. inline void double_add(int x,int y)
  23. {
  24. e[++cnt].to=y; e[cnt].v=1; e[cnt].next=head[x]; head[x]=cnt;
  25. e[++cnt].to=x; e[cnt].v=-1; e[cnt].next=head[y]; head[y]=cnt;
  26. }
  27. inline int gcd(int n,int m)
  28. {
  29. return m?gcd(m,n%m):n;
  30. }
  31. inline int min(int a,int b)
  32. {
  33. return a<b?a:b;
  34. }
  35. inline int max(int a,int b)
  36. {
  37. return a>b?a:b;
  38. }
  39. inline void BFS(int s)
  40. {
  41. register int i,H=0,T=1; vis[s]=1; q[1]=s;
  42. while (H<T)
  43. {
  44. int now=q[++H];
  45. for (i=head[now];~i;i=e[i].next)
  46. if (vis[e[i].to]) ans=gcd(ans,dis[now]-dis[e[i].to]+e[i].v); else
  47. {
  48. dis[e[i].to]=dis[now]+e[i].v; vis[e[i].to]=1; q[++T]=e[i].to;
  49. MIN=min(MIN,dis[e[i].to]); MAX=max(MAX,dis[e[i].to]);
  50. }
  51. }
  52. }
  53. int main()
  54. {
  55. //freopen("CODE.in","r",stdin); freopen("CODE.out","w",stdout);
  56. register int i; read(n); read(m);
  57. memset(head,-1,sizeof(head)); memset(e,-1,sizeof(e));
  58. for (i=1;i<=m;++i)
  59. read(x),read(y),double_add(x,y);
  60. for (i=1;i<=n;++i)
  61. if (!vis[i])
  62. {
  63. MAX=MIN=0; BFS(i);
  64. sum+=MAX-MIN+1;
  65. }
  66. if (ans<0) ans=-ans;
  67. if (ans)
  68. {
  69. if (ans<3) return puts("-1 -1"),0;
  70. for (lans=3;lans<ans&&ans%lans;++lans);
  71. return printf("%d %d",ans,lans),0;
  72. }
  73. if (sum<3) return puts("-1 -1"),0;
  74. return printf("%d 3",sum),0;
  75. }

DFS版CODE

  1. #include<cstdio>
  2. #include<cctype>
  3. #include<cstring>
  4. using namespace std;
  5. const int N=100005,M=1000005;
  6. struct edge
  7. {
  8. int to,next,v;
  9. }e[M<<1];
  10. int head[N],dis[N],n,m,x,y,ans,lans,sum,cnt,MIN,MAX;
  11. bool vis[N];
  12. inline char tc(void)
  13. {
  14. static char fl[100000],*A=fl,*B=fl;
  15. return A==B&&(B=(A=fl)+fread(fl,1,100000,stdin),A==B)?EOF:*A++;
  16. }
  17. inline void read(int &x)
  18. {
  19. x=0; char ch; while (!isdigit(ch=tc()));
  20. while (x=(x<<3)+(x<<1)+ch-'0',isdigit(ch=tc()));
  21. }
  22. inline void double_add(int x,int y)
  23. {
  24. e[++cnt].to=y; e[cnt].v=1; e[cnt].next=head[x]; head[x]=cnt;
  25. e[++cnt].to=x; e[cnt].v=-1; e[cnt].next=head[y]; head[y]=cnt;
  26. }
  27. inline int gcd(int n,int m)
  28. {
  29. return m?gcd(m,n%m):n;
  30. }
  31. inline int min(int a,int b)
  32. {
  33. return a<b?a:b;
  34. }
  35. inline int max(int a,int b)
  36. {
  37. return a>b?a:b;
  38. }
  39. inline void DFS(int now)
  40. {
  41. register int i; vis[now]=1;
  42. for (i=head[now];~i;i=e[i].next)
  43. if (vis[e[i].to]) ans=gcd(ans,dis[now]-dis[e[i].to]+e[i].v);
  44. else MIN=min(MIN,dis[e[i].to]=(dis[now]+e[i].v)),MAX=max(MAX,dis[e[i].to]),DFS(e[i].to);
  45. }
  46. int main()
  47. {
  48. //freopen("CODE.in","r",stdin); freopen("CODE.out","w",stdout);
  49. register int i; read(n); read(m);
  50. memset(head,-1,sizeof(head)); memset(e,-1,sizeof(e));
  51. for (i=1;i<=m;++i)
  52. read(x),read(y),double_add(x,y);
  53. for (i=1;i<=n;++i)
  54. if (!vis[i])
  55. {
  56. MAX=MIN=0; DFS(i);
  57. sum+=MAX-MIN+1;
  58. }
  59. if (ans<0) ans=-ans;
  60. if (ans)
  61. {
  62. if (ans<3) return puts("-1 -1"),0;
  63. for (lans=3;lans<ans&&ans%lans;++lans);
  64. return printf("%d %d",ans,lans),0;
  65. }
  66. if (sum<3) return puts("-1 -1"),0;
  67. return printf("%d 3",sum),0;
  68. }

Luogu P1477 [NOI2008]假面舞会的更多相关文章

  1. 洛谷 P1477 [NOI2008]假面舞会

    题目链接 题目描述 一年一度的假面舞会又开始了,栋栋也兴致勃勃的参加了今年的舞会. 今年的面具都是主办方特别定制的.每个参加舞会的人都可以在入场时选择一 个自己喜欢的面具.每个面具都有一个编号,主办方 ...

  2. 【洛谷】1477:[NOI2008]假面舞会【图论】

    P1477 [NOI2008]假面舞会 题目描述 一年一度的假面舞会又开始了,栋栋也兴致勃勃的参加了今年的舞会. 今年的面具都是主办方特别定制的.每个参加舞会的人都可以在入场时选择一 个自己喜欢的面具 ...

  3. 【做题记录】[NOI2008] 假面舞会—有向图上的环与最长链

    luogu 1477 [NOI2008] 假面舞会 容易发现: 如果图中没有环,那么面具种数一定是所有联通块内最长链之和,最少为 \(3\) . 如果有环,则面具种数一定是所有环的大小的最大公约数. ...

  4. 图论 公约数 找环和链 BZOJ [NOI2008 假面舞会]

    BZOJ 1064: [Noi2008]假面舞会 Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 1655  Solved: 798[Submit][S ...

  5. [BZOJ1064][Noi2008]假面舞会

    [BZOJ1064][Noi2008]假面舞会 试题描述 一年一度的假面舞会又开始了,栋栋也兴致勃勃的参加了今年的舞会.今年的面具都是主办方特别定制的.每个参加舞会的人都可以在入场时选择一 个自己喜欢 ...

  6. NOI2008假面舞会

    1064: [Noi2008]假面舞会 Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 883  Solved: 462[Submit][Status] ...

  7. 【BZOJ1064】[Noi2008]假面舞会 DFS树

    [BZOJ1064][Noi2008]假面舞会 Description 一年一度的假面舞会又开始了,栋栋也兴致勃勃的参加了今年的舞会.今年的面具都是主办方特别定制的.每个参加舞会的人都可以在入场时选择 ...

  8. 1064: [Noi2008]假面舞会 - BZOJ

    Description 一年一度的假面舞会又开始了,栋栋也兴致勃勃的参加了今年的舞会.今年的面具都是主办方特别定制的.每个参加舞会的人都可以在入场时选择一 个自己喜欢的面具.每个面具都有一个编号,主办 ...

  9. 【BZOJ】1064: [Noi2008]假面舞会(判环+gcd+特殊的技巧)

    http://www.lydsy.com/JudgeOnline/problem.php?id=1064 表示想到某一种情况就不敢写下去了.... 就是找环的gcd...好可怕.. 于是膜拜了题解.. ...

随机推荐

  1. Fiddler 使用fiddler发送捕获的请求及模拟服务器返回

    使用fiddler发送捕获的请求及模拟服务器返回 by:授客 QQ:1033553122 1.做好相关监听及代理设置 略 2.发送捕获的请求 如图 3.模拟服务器返回 本例的一个目的是,根据服务器返回 ...

  2. Android View体系(二)实现View滑动的六种方法

    1.View的滑动简介 View的滑动是Android实现自定义控件的基础,同时在开发中我们也难免会遇到View的滑动的处理.其实不管是那种滑动的方式基本思想都是类似的:当触摸事件传到View时,系统 ...

  3. (网页)angularjs中的interval定时执行功能(转)

    转载博客园魔豆: 一个例子,用来显示当前实时时间,1秒钟刷新一次: <!DOCTYPE html> <html ng-app="myApp"> <he ...

  4. Scrum敏捷开发沉思录

    计算机科学的诞生,是世人为了用数字手段解决实际生活中的问题.随着时代的发展,技术的进步,人们对于现实世界中的问题理解越来越深刻,描述也越来越抽象,于是对计算机软件的需求也越来越高,越来越复杂,变化也越 ...

  5. LeetCode题解之Binary Tree Pruning

    1.题目描述 2.问题分析 使用递归 3.代码 TreeNode* pruneTree(TreeNode* root) { if (root == NULL) return NULL; prun(ro ...

  6. HDU ACM 1224 Free DIY Tour (SPFA)

    Free DIY Tour Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Tot ...

  7. C++中int型与string型互相转换(转)

    http://greatverve.cnblogs.com/archive/2012/10/24/cpp-int-string.html 本以为这么多年C#经验,学个C++没多难,现在发现错了.C++ ...

  8. "error lnk1158 无法运行rc.exe”解决方案

    最近使用VS2012编译时,出现" error lnk1158 无法运行rc.exe”的问题,无法编译生成.exe文件,连最基本的HelloWorld控制台程序都无法运行,重置了VS的默认设 ...

  9. 17秋 软件工程 团队第五次作业 Alpha Scrum11

    17秋 软件工程 团队第五次作业 Alpha Scrum11 今日完成的任务 世强:管理员头像图片上传和显示逻辑处理,活动添加及上传图片: 港晨:完成Web界面前后端对接: 树民:标准化后端接口格式: ...

  10. php 安装xdebug进行调试(phpstorm)

    一.下载xdebug xdebug官网:https://xdebug.org/download.php 在选择下载哪个版本的xdebug的时候需要注意了,下面有两种方法,让你准确的下载自己环境对应的x ...