HZOI2019 B. 那一天她离我而去 最小环
题目大意: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模板(好像没人用正解打)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 | #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; } |
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<queue> 5 #define ll long long 6 #define MAXN 10005 7 #define MAXM 40005 8 using namespace std; 9 ll t,n,m,ans=0x3f3f3f3f; 10 ll pre[MAXN],tot_e=1,to[MAXM<<1],nxt[MAXM<<1],w[MAXM<<1]; 11 void add(ll u,ll v,ll d){ 12 tot_e++,to[tot_e]=v,nxt[tot_e]=pre[u],pre[u]=tot_e,w[tot_e]=d; 13 } 14 bool vis[MAXM<<1]; 15 void dfs(ll x,ll res){ 16 if(res>ans) return ; 17 if(x==1){ 18 if(res!=0){ 19 ans=min(ans,res); 20 return ; 21 } 22 } 23 for(ll i=pre[x];i;i=nxt[i]){ 24 if(!vis[i]){ 25 vis[i]=1,vis[i^1]=1; 26 dfs(to[i],res+w[i]); 27 vis[i]=0,vis[i^1]=0; 28 } 29 } 30 } 31 ll dfn[MAXN],low[MAXN],dfs_order=0; 32 bool is_bridge[MAXM<<1]; 33 void tarjan(ll x,ll in_edge){ 34 dfn[x]=low[x]=++dfs_order; 35 for(ll i=pre[x];i;i=nxt[i]){ 36 ll y=to[i]; 37 if(!dfn[y]){ 38 tarjan(y,i); 39 low[x]=min(low[x],low[y]); 40 if(low[y]>low[x]) 41 is_bridge[i]=is_bridge[i^1]=1; 42 } 43 else if(i!=(in_edge^1)) 44 low[x]=min(low[x],dfn[y]); 45 } 46 } 47 bool belong[MAXN]; 48 void DFS(int x){ 49 belong[x]=1; 50 for(int i=pre[x];i;i=nxt[i]){ 51 int y=to[i]; 52 if(belong[y]||is_bridge[i]) continue; 53 DFS(y); 54 } 55 } 56 ll dis[MAXN]; 57 priority_queue< pair<ll, ll> > q; 58 bool visit[MAXN]; 59 void dijkstra(ll x){ 60 memset(dis,0x3f,sizeof(dis)); 61 dis[x]=0; 62 memset(visit,0,sizeof(visit)); 63 q.push(make_pair(-dis[x],x)); 64 while(!q.empty()){ 65 ll y=q.top().second;q.pop(); 66 if(visit[y]) continue; 67 visit[y]=1; 68 for(ll i=pre[y];i;i=nxt[i]){ 69 ll v=to[i],z=w[i]; 70 if(dis[v]>dis[y]+z){ 71 dis[v]=dis[y]+z; 72 q.push(make_pair(-dis[v],v)); 73 } 74 } 75 } 76 } 77 int main(){ 78 scanf("%lld",&t); 79 while(t--){ 80 scanf("%lld%lld",&n,&m); 81 if(n==m){ 82 for(ll i=1,u,v,d;i<=m;i++){ 83 scanf("%lld%lld%lld",&u,&v,&d); 84 add(u,v,d),add(v,u,d); 85 } 86 dfs(1,0); 87 if(ans==0x3f3f3f3f) ans=-1; 88 printf("%lld\n",ans); 89 ans=0x3f3f3f3f; 90 memset(pre,0,sizeof(pre)); 91 tot_e=1; 92 }else{ 93 for(ll i=1,u,v,d;i<=m;i++){ 94 scanf("%lld%lld%lld",&u,&v,&d); 95 add(u,v,d),add(v,u,d); 96 } 97 for(ll i=1;i<=n;i++){ 98 if(!dfn[i]) tarjan(i,0); 99 } 100 DFS(1); 101 for(ll i=pre[1];i;i=nxt[i]){ 102 if(is_bridge[i]||!belong[to[i]]) continue; 103 ll temp=w[i]; 104 w[i]=w[i^1]=0x3f3f3f3f; 105 dijkstra(1); 106 ans=min(ans,dis[to[i]]+temp); 107 w[i]=w[i^1]=temp; 108 } 109 if(ans==0x3f3f3f3f) ans=-1; 110 printf("%lld\n",ans); 111 ans=0x3f3f3f3f; 112 tot_e=1,dfs_order=0; 113 memset(pre,0,sizeof(pre)); 114 memset(dfn,0,sizeof(dfn)); 115 memset(is_bridge,0,sizeof(is_bridge)); 116 } 117 } 118 return 0; 119 }
更多算法:
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 开发中对象命名的一点思考
· .NET Core内存结构体系(Windows环境)底层原理浅谈
· C# 深度学习:对抗生成网络(GAN)训练头像生成模型
· .NET 适配 HarmonyOS 进展
· .NET 进程 stackoverflow异常后,还可以接收 TCP 连接请求吗?
· 本地部署 DeepSeek:小白也能轻松搞定!
· 基于DeepSeek R1 满血版大模型的个人知识库,回答都源自对你专属文件的深度学习。
· 在缓慢中沉淀,在挑战中重生!2024个人总结!
· 如何给本地部署的DeepSeek投喂数据,让他更懂你
· 大人,时代变了! 赶快把自有业务的本地AI“模型”训练起来!