HZOI 那一天她离我而去

题目描述

她走的悄无声息,消失的无影无踪。
至今我还记得那一段时间,我们一起旅游,一起游遍山水。到了最终的景点,她却悄无声息地消失了,只剩我孤身而返。
现在我还记得,那个旅游区可以表示为一张由nnn个节点mmm条边组成无向图。我故地重游,却发现自己只想尽快地结束这次旅游。我从景区的出发点(即 1 号节点)出发,却只想找出最短的一条回路重新回到出发点,并且中途不重复经过任意一条边。
即:我想找出从出发点到出发点的小环。

输入格式

每个测试点有多组测试数据
第一行有一个正整数T,(T10)表示数据组数
接下来对于每组数据,第一行有两个正整数 n,m,(n,m104) 分别代表图的点数和边数
接下来有mmm行,每行三个整数u,v,du,v,du,v,d表示u,vu,vu,v之间存在一条长度为 d,(d103)的路径
保证不存在重边,自环。

输出格式

对于每组测试数据,输出题目中所求的最小环的长度。
无解输出 -1

 

背景

  看完这题我得出了一个结论: 矫情的人是不会有女朋友的。

  我以为我打完t1之后就可以切掉t2,但实际上。。。。

  t2是屑。

  这题没啥思维难度,重点在于代码的书写。
 
  调了我一上午。

思路分析

  虽然这题没啥思维难度,但是没思路的还是跟着我再梳理一遍吧。

  首先,我们读题发现这题要求最小环。

  ?????我没学过这种神犇犇算法,你呢?

  但是,出题人还没高明到自创算法来考你。

  所以这一定是学过的算法。

  跟最小环有关的算法是什么呢?

  emmmm。。。图论啊?最短路?

  谈起图论,最基础的就是各种最短路的求法,什么迪姐斯特拉啊,什么死帕法啊,什么弗洛易得啊?全都是图论最熟悉的东西。

  最 (最)√

  短 (小)√

  路 (环) ×

  还不错,匹配了两个,想必这两个肯定有关系 【瞎扯

  那么我们来仔细回顾一下,原话是怎么说的

      找出从出发点到出发点的小环。

  既然起点(终点)已经确定了,那么我们不妨画个图来看看。

  

  这可是我辛辛苦苦手画出来的图啊,HZ条件好艰苦啊,我之前都画图工具画的又快又好啊,苦苦

  好的我们看这张图,假设边权都是1.

  那么怎么才能找到 { 1,2, 4,5 } 这个集合呢?

  我们发现,其实我们只要跑2和4之间的最短路,再加上1 就是这个集合。

  那我们再画几张图观察一下。

  。。。。。。。。。。。。。

  。。。。。。。。。。。。。

    有没有发现一个结论?

    在与1相连的节点中跑最短路,有且只有一条最短路是被包含在最小环中的。【相等什么的忽略不计

  那么最小环的长度,就是这条最短路的长度加上 两个节点与1之间的距离。

  那好,我们来尝试使用一下这个结论。

  我们记录和1相连的所有节点,存在 yh [ i ] 数组中。

  建边的时候,直接把与1相连的边全部 ban 掉。

  然后分别记录每两个之间的最短路,加上yh与1之间的距离,取最小,即为答案。

  这里注意,最好不要SPFA。


细节问题

  当你写完上面的做法的时候,好,样例过了就是过了,但是实际上并没有,你TLE了。

  ??????????

  ??????????

  算法没出错啊?究竟是哪里的问题呢?

  仔细想想,复杂度不太对啊?最大可能 n2logn ?【如果不对请留言告诉我

  这不就完全炸掉了吗?

  那怎么办啊?

  这个时候来仔细想想,究竟是什么地方出现了问题呢?

  由于建的是双向边,那么我们跑 最短路的时候很可能就不断的在重复。

  怎么样才能解决掉这个问题呢?

  这里介绍一个玄学优化 【正常人想不到就很正常

  我们对于每一个与1相连的点进行 二进制拆分

  这样我们的点就可以被被分成好多个两组。

  一组做起点,一组做终点,在这两组之间跑最短路。

  写对就AC了,加油吧!


代码实现

#include<iostream>
#include<cstdio>
#include<cmath>
#include<queue>
#include<cstring>
using namespace std;

struct ss{
    int to,nxt,val;
}jd[80010];
int t,n,m,dis[10010],yh[10010],cnt;
int head[10010],ecnt,vis[10010],dis1[10010],ans;
int cnt1,ed[10010];
priority_queue<pair<int,int> >q;

inline void add(int a,int b,int c) { jd[++ecnt].to=b; jd[ecnt].nxt=head[a]; jd[ecnt].val=c; head[a]=ecnt; return; } void clear() { cnt=0; ecnt=0; memset(head,0,sizeof head); memset(dis,0x3f,sizeof dis); memset(yh,0,sizeof yh); ans=100000000; return; } void dij() { while(!q.empty()) { while(vis[q.top().second]&&!q.empty()) q.pop(); if(q.empty()) break; int u=q.top().second; q.pop(); vis[u]=1; for(int v=head[u];v;v=jd[v].nxt) { int y=jd[v].to; int z=jd[v].val; if(vis[y]) continue; if(dis1[y]>dis1[u]+z) { dis1[y]=dis1[u]+z; q.push(make_pair(-dis1[y],y)); } } } return; } int main() { scanf("%d",&t); while(t--) { clear(); scanf("%d%d",&n,&m); int x,y,z; for(int i=1;i<=m;i++) { scanf("%d%d%d",&x,&y,&z); if(x==1||y==1){ if(x==1) swap(x,y); yh[++cnt]=x; dis[x]=z; } else{ add(x,y,z); add(y,x,z); } } int k=0; while((1<<k)<=n) k++; for(int i=0;i<k;i++) { memset(dis1,0x3f,sizeof dis1); memset(vis,0,sizeof vis); memset(ed,0,sizeof ed); cnt1=0; while(!q.empty()) q.pop(); for(int j=1;j<=cnt;j++) { if(((1<<i)&yh[j])) { q.push(make_pair(-dis[yh[j]],yh[j])); dis1[yh[j]]=dis[yh[j]]; } else{ ed[++cnt1]=yh[j]; } } dij(); for(int j=1;j<=cnt1;j++) ans=min(ans,dis1[ed[j]]+dis[ed[j]]); } if(ans<100000000) printf("%d\n",ans); else printf("-1\n"); } return 0; }

AC啦!!!!!!!!!!

猜你喜欢

转载自www.cnblogs.com/qxyzili--24/p/11220786.html
今日推荐