题目大意:https://www.cnblogs.com/Juve/articles/11219089.html

那一天,我们......行啦,不要帮出题人脑补画面了,我们来正经的题解

我们发现我们可以把与1号节点相连的所有节点取出,如果我们把最小环在1号节点处断开,那么最小环断成的链一定是以这些节点中的某一个节点作为起点,另一个节点作为终点的一条路路径。
如果不考虑时间复杂度,我们完全可以枚举作为起点的节点,每次都跑一遍最短路来更新答案。
但是上面的做法肯定会爆炸,所以我们考虑如何降低复杂度。

我们考虑把所有的节点分为两组,一组中的所有点作为起点,另一组中的所有点作为终点,一起跑最短路,更新答案。
如此我们发现只要我们能够保证真正贡献答案的一对节点会在某一次分组当中被分到不同组,我们就可以保证算法的正确性。
因为起点与终点的编号肯定不相同,于是我们可以按照二进制分组,枚举每个二进制位,按照当前二进制位的0/1情况来进行分组。

我看好像没有人用这种方法的,其实dij就可以过,用dij求1号节点开始的最小环

别告诉我你不会求最小环。

我们枚举1号点连接的每一条边,设起点为fr[i],终点为to[i],

先把这条边权变成0x3f3f3f3f,跑dij,求出此时fr[i]到to[i]的最短路,再加上原来这条边的权值就是一个环的大小,

更新答案:ans=min(dis[to[i]]+w[i]);

就是把fr[i]和to[i]间的边断开后两点间的最短路加上原来两点间的距离取最小值

原来博主想用tarjan求边双,然后在1号节点所在的边双中跑dij,但时间并没有下去

还有注意给边编号从2开始,这样i和i^1是一对双向边

本来一道很有思维量的题被做成了dijkstra模板(好像没人用正解打)

#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
#define ll long long
#define MAXN 10005
#define MAXM 40005
using namespace std;
ll t,n,m,ans=0x3f3f3f3f;
ll pre[MAXN],tot_e=1,to[MAXM<<1],nxt[MAXM<<1],w[MAXM<<1];
void add(ll u,ll v,ll d){
tot_e++,to[tot_e]=v,nxt[tot_e]=pre[u],pre[u]=tot_e,w[tot_e]=d;
}
ll dis[MAXN];
priority_queue< pair<ll, ll> > q;
bool visit[MAXN];
void dijkstra(ll x){
memset(dis,0x3f,sizeof(dis));
dis[x]=0;
memset(visit,0,sizeof(visit));
q.push(make_pair(-dis[x],x));
while(!q.empty()){
ll y=q.top().second;q.pop();
if(visit[y]) continue;
visit[y]=1;
for(ll i=pre[y];i;i=nxt[i]){
ll v=to[i],z=w[i];
if(dis[v]>dis[y]+z){
dis[v]=dis[y]+z;
q.push(make_pair(-dis[v],v));
}
}
}
}
int main(){
scanf("%lld",&t);
while(t--){
scanf("%lld%lld",&n,&m);
for(ll i=1,u,v,d;i<=m;i++){
scanf("%lld%lld%lld",&u,&v,&d);
add(u,v,d),add(v,u,d);
}
for(ll i=pre[1];i;i=nxt[i]){
ll temp=w[i];
w[i]=w[i^1]=0x3f3f3f3f;
dijkstra(1);
ans=min(ans,dis[to[i]]+temp);
w[i]=w[i^1]=temp;
}
if(ans==0x3f3f3f3f) ans=-1;
printf("%lld\n",ans);
ans=0x3f3f3f3f;
tot_e=1;
memset(pre,0,sizeof(pre));
}
return 0;
}
 #include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
#define ll long long
#define MAXN 10005
#define MAXM 40005
using namespace std;
ll t,n,m,ans=0x3f3f3f3f;
ll pre[MAXN],tot_e=,to[MAXM<<],nxt[MAXM<<],w[MAXM<<];
void add(ll u,ll v,ll d){
tot_e++,to[tot_e]=v,nxt[tot_e]=pre[u],pre[u]=tot_e,w[tot_e]=d;
}
bool vis[MAXM<<];
void dfs(ll x,ll res){
if(res>ans) return ;
if(x==){
if(res!=){
ans=min(ans,res);
return ;
}
}
for(ll i=pre[x];i;i=nxt[i]){
if(!vis[i]){
vis[i]=,vis[i^]=;
dfs(to[i],res+w[i]);
vis[i]=,vis[i^]=;
}
}
}
ll dfn[MAXN],low[MAXN],dfs_order=;
bool is_bridge[MAXM<<];
void tarjan(ll x,ll in_edge){
dfn[x]=low[x]=++dfs_order;
for(ll i=pre[x];i;i=nxt[i]){
ll y=to[i];
if(!dfn[y]){
tarjan(y,i);
low[x]=min(low[x],low[y]);
if(low[y]>low[x])
is_bridge[i]=is_bridge[i^]=;
}
else if(i!=(in_edge^))
low[x]=min(low[x],dfn[y]);
}
}
bool belong[MAXN];
void DFS(int x){
belong[x]=;
for(int i=pre[x];i;i=nxt[i]){
int y=to[i];
if(belong[y]||is_bridge[i]) continue;
DFS(y);
}
}
ll dis[MAXN];
priority_queue< pair<ll, ll> > q;
bool visit[MAXN];
void dijkstra(ll x){
memset(dis,0x3f,sizeof(dis));
dis[x]=;
memset(visit,,sizeof(visit));
q.push(make_pair(-dis[x],x));
while(!q.empty()){
ll y=q.top().second;q.pop();
if(visit[y]) continue;
visit[y]=;
for(ll i=pre[y];i;i=nxt[i]){
ll v=to[i],z=w[i];
if(dis[v]>dis[y]+z){
dis[v]=dis[y]+z;
q.push(make_pair(-dis[v],v));
}
}
}
}
int main(){
scanf("%lld",&t);
while(t--){
scanf("%lld%lld",&n,&m);
if(n==m){
for(ll i=,u,v,d;i<=m;i++){
scanf("%lld%lld%lld",&u,&v,&d);
add(u,v,d),add(v,u,d);
}
dfs(,);
if(ans==0x3f3f3f3f) ans=-;
printf("%lld\n",ans);
ans=0x3f3f3f3f;
memset(pre,,sizeof(pre));
tot_e=;
}else{
for(ll i=,u,v,d;i<=m;i++){
scanf("%lld%lld%lld",&u,&v,&d);
add(u,v,d),add(v,u,d);
}
for(ll i=;i<=n;i++){
if(!dfn[i]) tarjan(i,);
}
DFS();
for(ll i=pre[];i;i=nxt[i]){
if(is_bridge[i]||!belong[to[i]]) continue;
ll temp=w[i];
w[i]=w[i^]=0x3f3f3f3f;
dijkstra();
ans=min(ans,dis[to[i]]+temp);
w[i]=w[i^]=temp;
}
if(ans==0x3f3f3f3f) ans=-;
printf("%lld\n",ans);
ans=0x3f3f3f3f;
tot_e=,dfs_order=;
memset(pre,,sizeof(pre));
memset(dfn,,sizeof(dfn));
memset(is_bridge,,sizeof(is_bridge));
}
}
return ;
}

tarjan的复杂算法

更多算法:

https://www.cnblogs.com/Juve/articles/11220105.html

HZOI2019 B. 那一天她离我而去 最小环的更多相关文章

  1. HZOI2019 A. 那一天我们许下约定 dp

    题目大意:https://www.cnblogs.com/Juve/articles/11219089.html 读这道题的题目让我想起了... woc我到底在想什么?好好写题解,现在不是干那个的时候 ...

  2. HZOI2019 超级树 dp

    题面:https://www.cnblogs.com/Juve/articles/11207540.html(密码)————————————————>>> 题解: 官方题解: 考虑d ...

  3. HZOI2019 砍树 整除分块

    题目链接:https://www.cnblogs.com/Juve/articles/11207540.html(密码你懂的)——————————>> 这题... 一开始想的二分,但此题不 ...

  4. HZOI2019 星际旅行 欧拉路

    题目大意:https://www.cnblogs.com/Juve/articles/11207540.html—————————> 题解:网上都是一句话题解:将所有的边拆成两条,问题变成去掉两 ...

  5. HZOI2019熟练剖分(tree)

    题目大意:https://www.cnblogs.com/Juve/articles/11186805.html 题解: 先给出官方题解: 其实这题跟期望没什么关系,因为E=$\sum_\limits ...

  6. HZOI2019建造游乐园(play)组合数学,欧拉图

    题目:https://www.cnblogs.com/Juve/articles/11186805.html(密码是我的一个oj用户名) solution: 反正我是想不出来... 题目大意就是要求出 ...

  7. HZOI2019序列

    题目链接:https://www.cnblogs.com/Juve/articles/11186805.html(密码是我的一个oj用户名) 题解: 这题我考试打的暴力,只有5分. 一开始理解错题意了 ...

  8. 【暑假集训】HZOI2019 Luogu P1006 传纸条 二三四维解法

    写三次丢失两次,我谔谔,以后再不在博客园先保存我就去死 题目内容 洛谷链接 小渊和小轩是好朋友也是同班同学,他们在一起总有谈不完的话题.一次素质拓展活动中,班上同学被安排坐成一个\(m\)行.\(n\ ...

  9. 【暑假集训】HZOI2019 水站 多种解法

    题目内容 已知有一个\(n\)层的水站: \(W_i\)表示未操作之前第\(i\)层的已有水量: \(L_i\)表示第\(i\)个水站能够维持或者储存的水的重量: 表示在第\(P_i\)层进行减压放水 ...

随机推荐

  1. socket 上传文件

    """ "" server.py """服务端 """import socketimpor ...

  2. 初识Qgis

    折腾了一天,qgis终于能在跟了自己8年的本本上顺利打开了,官网先后下载了3.8和3.4版本的都出现了同样的问题,"could not load qgis_app.dll",goo ...

  3. MySQL语句基本操作增删改查

    select * from 表名; --------->效率低

  4. Windows tasklist

    TASKLIST [/S system [/U username [/P [password]]]]         [/M [module] | /SVC | /V] [/FI filter] [/ ...

  5. day21 生成器,列表解析,三元表达式

    Python之路,Day9 = Python基础9 判断可迭代对象和迭代器 from collections import Iterable, Iterator # 导入模块功能,用来判断对象是否为I ...

  6. Java笔记 - GUI编程

    一.图形界面开发 1.AWT开发 AWT(Abstract Window Toolkit)在Windows.Linux提供的图形窗口之上,再次进行了抽象,为不同语言开发的程序提供统一定义的图形接口,可 ...

  7. iOS开发之SceneKit框架--SCNParametricGeometry.h

    1.SCNParametricGeometry简介 SCNParametricGeometry用于创建简单的3D模型,比如SCNPlane 平面.SCNPyramid 锥形(金字塔).SCNBox 立 ...

  8. 【bzoj 2870】 最长道路tree

    题目 边分治 边分和点分相比就是找到一条重心边,考虑所有经过这条边的路径,之后断开这条边分成两个联通块,继续分治 由于每次分治重心是一条边,所以只会产生两个联通块,考虑两个联通块显然要比像点分那样考虑 ...

  9. USACO 2008 November Gold Cheering up the Cows /// MST oj24381

    题目大意: 输入n,p:n个点,p条路 接下来n行输入c[]:在各个点需要花费的时间 接下来p行输入u,v,w:u点到v点的路需要花费时间w 求经过所有点且最后回到起点的最少花费时间 https:// ...

  10. SwiftUI 实现Draggesture效果

    今天闲来无事,使用SwiftUI 实现拖动,并且返回的动态效果.代码不多..... 效果如下: 代码如下: import SwiftUI import Combine class KBDragObje ...