首页 技术 正文
技术 2022年11月6日
0 收藏 577 点赞 919 浏览 3805 个字

题目大意: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

上一篇: JZOJ5967 常数国
下一篇: 伸缩布局flex
相关推荐
python开发_常用的python模块及安装方法
adodb:我们领导推荐的数据库连接组件bsddb3:BerkeleyDB的连接组件Cheetah-1.0:我比较喜欢这个版本的cheeta…
日期:2022-11-24 点赞:878 阅读:9,110
Educational Codeforces Round 11 C. Hard Process 二分
C. Hard Process题目连接:http://www.codeforces.com/contest/660/problem/CDes…
日期:2022-11-24 点赞:807 阅读:5,584
下载Ubuntn 17.04 内核源代码
zengkefu@server1:/usr/src$ uname -aLinux server1 4.10.0-19-generic #21…
日期:2022-11-24 点赞:569 阅读:6,431
可用Active Desktop Calendar V7.86 注册码序列号
可用Active Desktop Calendar V7.86 注册码序列号Name: www.greendown.cn Code: &nb…
日期:2022-11-24 点赞:733 阅读:6,202
Android调用系统相机、自定义相机、处理大图片
Android调用系统相机和自定义相机实例本博文主要是介绍了android上使用相机进行拍照并显示的两种方式,并且由于涉及到要把拍到的照片显…
日期:2022-11-24 点赞:512 阅读:7,837
Struts的使用
一、Struts2的获取  Struts的官方网站为:http://struts.apache.org/  下载完Struts2的jar包,…
日期:2022-11-24 点赞:671 阅读:4,920