题目

题目大意

给你一个每条边正反权值不一定相同的无向图,求起点为111点的最小环。


思考历程

一看到这题,就觉得是一个经典模型。

然后思考先前做过最小环的经历,发现没个卵用。

我突然想到,既然这一个环是在111点上的,那么肯定有两条边和111相连。

一个很显然的思路就是,枚举与111相连的边,然后计算带着这条边最小环。

首先处理一个最短路,并且在带一个前驱,表示从哪一个边转移过来。

枚举和111相连的每一条边,设另一个点为xxx,如果xxx的前驱不是111,那么直接为dis(x)+len(x,1)dis(x)+len(x,1)dis(x)+len(x,1)。

问题来了,前驱是111怎么办?

有一个很暴力的思路,就是将这条边删掉,再跑一遍最短路径。

时间肯定会炸啊!(后来:呵呵)

其实我们只需要保证再求一个最短路,使得这个最短路的前驱不是111,那就可以搞定了。

我们还是要保证这个尽量短,所以这是一个次短路。

现在的瓶颈就是,如何求次短路呢?

于是我懵逼了,求次短路万一不能保证时间复杂度怎么办?

最后想不到什么稳妥的解法,于是暴力一点,就将边删去,然后跑最短路。

结果……100分?

出题人啊,想想你的数据,让一个O(m2)O(m^2)O(m2)的蒟蒻都过了。


水法

特意新增这个栏目……

其实我的这个做法算是水法吧,只不过这明明是60分的方法啊……

SLS大佬,用暴力跑过了这题!

怎么暴力?用IDA*!

二分一下环的长度,然后递归来干!

设一个估价函数,就是它到111的最短路径。

然后加了各种剪枝……

比如说,如果在递归的过程当中出现了环,就退出……

反正是一堆优化。

然后轻易地水过这题。


正解

先说一说第一个正解。

其实我想得已经非常接近了,就是求最短路和次短路啊!

怎么求次短路呢?题解中解释得有些笼统,就是说用SPFA不停迭代直到稳定为止。

原来,事情并没有我想象中的那么复杂……

就是在转移的时候多了一个次短路的转移而已……其实也不用特意在意它是次短的,只需要第一条边和最短路不一样就行了。

然后我有一个问题,如果有点xxx,它转移到yyy,不如yyy的次短路,所以会被踢掉;可是如果它继续从yyy转移到zzz,那又能更新zzz的次短路。有没有这种情况呢?

如果有这种情况,那就是yyy原来的次短路和zzz的最短路的初始边相同,但xxx的次短路和zzz的最短路的初始边不同,所以就有可能转移过去。

某大爷解释道:如果yyy原来的次短路和zzz的最短路的初始边相同,那么yyy的最短路和zzz的最短路的初始边一定不同,那这也是可以转移过去的。

所以说,直接求在正确性上似乎没有什么问题。

然后时间呢?

时间我就不清楚了,有点玄学。

然后就是一个比较正经的解法,时间复杂度绝对优秀(可以用Dijkstra):

这个方法就是构造一个新图,在里面跑最短路。

首先我们将每一个点的最短路给算出来,并且记录它们最短路经过的边(记住是边!题解害死人!不过我没有受骗),记作firfirfir

设新图中源点为SSS.,汇点为TTT。(不要想到网络流去了!)

对于从111连出去的边e(1,x,len)e(1,x,len)e(1,x,len):

如果fir(x)=efir(x)=efir(x)=e,不要理它。

否则,就在新图中连(S,x,len)(S,x,len)(S,x,len)

对于从xxx连回111的边e(x,1,len)e(x,1,len)e(x,1,len):

如果fir(x)=efir(x)=efir(x)=e,连(x,T,len)(x,T,len)(x,T,len)

否则,连(S,T,dis(x)+len)(S,T,dis(x)+len)(S,T,dis(x)+len)

对于其它的边(u,v,len)(u,v,len)(u,v,len)

如果fir(u)=fir(v)fir(u)=fir(v)fir(u)=fir(v),就连(u,v,len)(u,v,len)(u,v,len)

否则连(S,u,dis(u)+len)(S,u,dis(u)+len)(S,u,dis(u)+len)

然后整个图就建完了,从SSS点跑一遍到TTT的最短路就好了。

这个方法真的是十分巧妙,具体是为什么呢?

我斟酌了很久……

我们试着分个类:

对于和111相连的边e(x,1)e(x,1)e(x,1),如果xxx的最短路径是从111开始,走其它的边到了xxx,那么答案显然是dis(x)+lendis(x)+lendis(x)+len,对应上面的(S,T,dis(x)+len)(S,T,dis(x)+len)(S,T,dis(x)+len)。那么xxx不会直接连到TTT,所以不会有从SSS出来,走向同道路回去的尴尬情况。

如果xxx的最短路径是从111直接走这条边到xxx的,通过上面我们建的图,我们可以发现,它在SSS这边没有,在TTT这边有,所以不可能走同一条边。

现在有一个问题,可能出现这样的情况:最小环和111相连的两个点,111到它们的最短路径都是直接从111走到它们,那样有没有可能算漏呢?

我们再看看边e(u,v)e(u,v)e(u,v)其中uuu和vvv都不是111。

如果fir(u)=fir(v)fir(u)=fir(v)fir(u)=fir(v),那么它们的最短路是从同一条边走过来的,不能直接组成环,所以按照原样。

否则,它们是可以形成一个环的。设xxx为边fir(u)fir(u)fir(u)的除111外的那一端的点,显然xxx的最短路是直接从111走过来的,可是现在这条路没了啊!(上面没有建出来)

不怕,直接连(S,v,dis(u)+len)(S,v,dis(u)+len)(S,v,dis(u)+len),直接连过去。

我们再回顾一下上面有没有可能算漏的问题,虽然说两个点和111相连的边不能直接连通,但是它们是可以用这种方式连通的啊!所以它们是可以被计算到的。

这样建图既可以保证所有合法的环都可以走,又可以扼杀从同一条边走回去的机会。

时间复杂度是很稳定的,毕竟只是求两遍最短路罢了,如果你打Dijkstra,那就不会被卡。由于我比较懒惰,所以还是打了SPFA。


代码

  1. using namespace std;
  2. #include <cstdio>
  3. #include <cstring>
  4. #include <algorithm>
  5. #define N 10000
  6. #define M 200000
  7. int n,m;
  8. struct EDGE{
  9. int to,len,num;
  10. EDGE *las;
  11. } e[M*4+1];
  12. int ne;
  13. EDGE *last1[N+2],*last2[N+2];
  14. inline void link(EDGE *last[],int u,int v,int len,int num){
  15. e[++ne]={v,len,num,last[u]};
  16. last[u]=e+ne;
  17. }
  18. int dis[N+2],fir[N+2];
  19. inline void SPFA(EDGE*[],int);
  20. int S,T;
  21. int ans=2147483647;
  22. int main(){
  23. scanf("%d%d",&n,&m);
  24. for (int i=1;i<=m;++i){
  25. int u,v,len1,len2;
  26. scanf("%d%d%d%d",&u,&v,&len1,&len2);
  27. link(last1,u,v,len1,i);
  28. link(last1,v,u,len2,i);
  29. }
  30. SPFA(last1,1);
  31. S=1,T=n+1;
  32. for (EDGE *ei=last1[1];ei;ei=ei->las)
  33. if (fir[ei->to]!=ei->num)
  34. link(last2,S,ei->to,ei->num,ei->len);
  35. for (int i=2;i<=n;++i)
  36. for (EDGE *ei=last1[i];ei;ei=ei->las)
  37. if (ei->to==1){
  38. if (fir[i]==ei->num)
  39. link(last2,i,T,ei->len,ei->num);
  40. else
  41. ans=min(ans,dis[i]+ei->len);//本来是S到T连这么一条边,实际上直接统计入答案也可以
  42. }
  43. else{
  44. if (fir[i]==fir[ei->to])
  45. link(last2,i,ei->to,ei->len,ei->num);
  46. else
  47. link(last2,S,ei->to,dis[i]+ei->len,ei->num);
  48. }
  49. SPFA(last2,S);
  50. ans=min(ans,dis[T]);
  51. printf("%d\n",ans);
  52. return 0;
  53. }
  54. #define an 1048575
  55. int q[an+2];
  56. bool inq[N+2];
  57. inline void SPFA(EDGE *last[],int S){
  58. memset(dis,127,sizeof dis);
  59. dis[S]=0;
  60. int h=-1,t=0;
  61. q[0]=S;
  62. inq[S]=1;
  63. do{
  64. ++h&=an;
  65. for (EDGE *ei=last[q[h]];ei;ei=ei->las)
  66. if (dis[q[h]]+ei->len<dis[ei->to]){
  67. dis[ei->to]=dis[q[h]]+ei->len;
  68. fir[ei->to]=((q[h]==1)?ei->num:fir[q[h]]);
  69. if (!inq[ei->to]){
  70. inq[ei->to]=1;
  71. q[++t&=an]=ei->to;
  72. }
  73. }
  74. inq[q[h]]=0;
  75. }
  76. while (h!=t);
  77. }

总结

首先,有的时候暴力出奇迹。

遇到某些题目的时候,如果想不出正解,那就试着用暴力来做,有时几个剪枝就可以得到好多好多的分数。

然后就是面对一些看似很难解的题目,试着转换一下模型,用各种奇妙的方式建立一个奇妙的东西。

[JZOJ2702] 【GDKOI2012模拟02.01】探险的更多相关文章

  1. jzoj2700 【GDKOI2012模拟02.01】数字

    传送门:https://jzoj.net/senior/#main/show/2700 [题目大意] 令n为正整数,S(n)为n的各位数字之和,令

  2. jzoj2701 【GDKOI2012模拟02.01】矩阵

    传送门:https://jzoj.net/senior/#main/show/2701 [题目大意] 给出矩阵A,求矩阵B,使得

  3. http://www.cnblogs.com/draem0507/archive/2013/02/01/2889317.html

    http://www.cnblogs.com/draem0507/archive/2013/02/01/2889317.html

  4. oracle问题 《经由直接路径由 EXPORT:V10.02.01 创建的导出文件 IMP-00013: 只有 DBA 才能导入由其他 DBA 导出的文件》

    问题:  经由直接路径由 EXPORT:V10.02.01 创建的导出文件 : 只有 DBA 才能导入由其他 DBA 导出的文件 解决方法:用sys 登录,给当前用户授权,授权语句:grant dba ...

  5. 2016.02.01日,UdoOS系统项目正式开通了

    2016.02.01日,UdoOS系统项目正式开通了,源代码即将开放 Copyright (c) 2016

  6. 02.02.01 第1章 简介及基础操作(Power BI商业智能分析)

    02.02.01.01 powerbi简介 00:10:59 02.02.01.02 query数据导入 00:03:26 具体操作实例如下: 02.02.01.03导入access数据 00:05: ...

  7. http://www.cnblogs.com/langtianya/archive/2013/02/01/2889682.html

    http://www.cnblogs.com/langtianya/archive/2013/02/01/2889682.html

  8. 2020.02.01【NOIP提高组】模拟B 组总结反思——数列(sequence) 树 【2012东莞市选】时间流逝 挖掘机技术哪家强

    T1 数列(sequence) 比赛时 我自以为是地打了简简单单一个判断--- 之后 Waiting-- T2 2753. 树(tree) 比赛时 这题我居然比赛时也想了很久,可能是因为我太懒,我很早 ...

  9. adb调试命令详解-2016.02.01

    adb(Android Debug Bridge),调试桥可以让设备的调试监测过程在远端进行,而不必在运行实际运行应用的设备上,方便调试的输出. 1 命令详解 a 查看帮助信息         adb ...

随机推荐

  1. Java-javaFx库运用-时钟显示

    JavaFx是开发Java GUI程序的新框架.JavaFX应用可以无缝地在桌面或web浏览器中运行.具有内建的2D.3D动画支持,以及视频和音频的回放功能,可以作为一个应用独立运行或者在浏览器中运行 ...

  2. IP总结

    网络层向上只提供无连接的.尽最大努力支付的数据报服务 IP地址,32位,分为两部分,网络和主机标示 IP地址分类: A类:0开头,1-8位为网络标示 B类:10开头,1-16位为网络标示 C类:110 ...

  3. Aliyun 安装NPM 总是3.5.2 解决方案

    由于默认的命令 阿里云安装的 Node 是 8.x 版本 导致NPM 一直安装的都是 3.5.2 版本,死活升级不上去 最后手动安装指定版本解决 wget -qO- https://deb.nodes ...

  4. PAT_A1094#The Largest Generation

    Source: PAT A1094 The Largest Generation (25 分) Description: A family hierarchy is usually presented ...

  5. 剑指offer——26树的子结构

    题目描述 输入两棵二叉树A,B,判断B是不是A的子结构.(ps:我们约定空树不是任意一个树的子结构)   题解: 注意,所谓的子结构,是树的形状和值相同,并非判断B是不是A的一部分[如果是这样,那就是 ...

  6. Quartz2作业监听

    在本教程中,我们将展示/介绍如何创建一个JobListener,跟踪运行工作状态在作业完成等. P.S 这个例子是Quartz 2.1.5 1. Quartz 作业 作业 - 用于打印一个简单的信息, ...

  7. jenkins自动化部署jar包(2)

    1.自动化部署流程: svn代码-----jenkins------linux运行 环境: 我这里为了测试:svn,和linux放在阿里云上面.jenkins放在本地windos电脑上运行的 2.下载 ...

  8. 关于UIPageViewController去除边缘点击手势

    如果page上方还有一层UI控件的话,不去除边缘点击手势会造成手势的冲突干扰. 首先我做的处理是设置pageView的手势代理 for (UIGestureRecognizer *gr in _pag ...

  9. iOS开发系列-iOS布局相关

    LayoutSubViews 需要在某个View调整子视图的位置时,可以重写. 以下情况会出发LayoutSubViews方法的调用 init初始化不会触发layoutSubviews,但是是用ini ...

  10. heartbeat 高可用

    转载来自 http://www.cnblogs.com/liwei0526vip/p/6391833.html 使用HeartBeat实现高可用HA的配置过程详解 一.写在前面 HA即(high av ...