HZOI2019 B. 那一天她离我而去 最小环

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

那是寒假里的一天,我们......行啦,不要脑补画面了,我们来正经的题解

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

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

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

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

我们枚举1号点连接的每一条边,先把这条边权变成0x3f3f3f3f,跑dij,更新答案:ans=min(dis[to[i]]+w[i]);

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

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

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

#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;
}
  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 }
tarjan的复杂算法

猜你喜欢

转载自www.cnblogs.com/Juve/p/11220111.html
今日推荐