单身三连之二

Posted hz-rockstar

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了单身三连之二相关的知识,希望对你有一定的参考价值。

一道正解不可靠,暴力碾标算的题。

题目大意:

  有一张无向图,求经过起点的最小环。(点数N<=1×104,边数M<=4×104,多测,无解输出-1)

题解:

  先判断图的合法性。从起点开始dfs,判断能否从其他路径回到起点,若搜索失败,则一定无解。

  已知图是合法的,我们可以将连接起点的边断掉,对每个起点连接的点跑一遍Dijkstra,求出两点间的最短路径,然后枚举更新,用两个不同的和起点相连的点去更新答案。

  注意细节处理和赋极大值,多测要清空。

  理论复杂度O(N2logM),不过由于和起点相连的点较少,复杂度远远达不到上界。如果遇到菊花图,则Dijkstra表现会非常优秀,不易被卡掉。

  此题用spfa或A*也可做。spfa用法和Dijkstra相似。A*搜索时要注意不能沿已走过的边回去,剪枝就行,理论复杂度最低,不过码量较大。

Code:

 

技术图片
  1 #include<iostream>
  2 #include<cstdio>
  3 #include<queue>
  4 #include<cstring>
  5 using namespace std;
  6 const int N=10010;
  7 const int M=40010;
  8 const int inf=99999999;
  9 int t,n,m,nm=1;
 10 int fi[N],in[N],d[N],de[N];
 11 bool vis[N],v[N];
 12 struct edge
 13     int u,v,l,ne;
 14 e[M<<1];
 15 struct point
 16     int id,d;
 17     friend bool operator < (const point a1,const point a2)
 18     
 19         return a1.d>a2.d;
 20     
 21 p[N];
 22 priority_queue<point> q;
 23 void add(int x,int y,int z)
 24 
 25     e[++nm].u=x;
 26     e[nm].v=y;
 27     e[nm].l=z;
 28     e[nm].ne=fi[x];
 29     fi[x]=nm;
 30 
 31 int read()
 32 
 33     int s=0;
 34     char c=getchar();
 35     while(c<0||c>9)    c=getchar();
 36     while(c>=0&&c<=9)
 37         s=(s<<3)+(s<<1)+c-0;
 38         c=getchar();
 39     
 40     return s;
 41 
 42 void clean()
 43 
 44     memset(fi,0,sizeof(fi));    
 45     memset(in,0,sizeof(in));
 46     memset(vis,false,sizeof(vis));
 47     memset(v,false,sizeof(v));
 48     memset(d,0,sizeof(d));
 49     for(int i=1;i<=10000;i++)    de[i]=inf;
 50     nm=1;
 51 
 52 bool dfs(int x,int p)
 53 
 54     vis[x]=true;
 55     for(int i=fi[x];i!=0;i=e[i].ne)
 56         int y=e[i].v;
 57         if(y==1&&p!=1)    return true;
 58         if(vis[y])    continue;
 59         if(dfs(y,x))    return true;
 60     
 61     return false;
 62 
 63 void Dij(int now)
 64 
 65     for(int i=1;i<=n;i++)
 66         p[i].d=inf;
 67         v[i]=false;
 68     
 69     p[now].d=0;
 70     q.push(p[now]);
 71     while(!q.empty())
 72         point x=q.top();q.pop();
 73         if(v[x.id])
 74             continue;
 75         v[x.id]=true;
 76         for(int i=fi[x.id];i!=0;i=e[i].ne)
 77             int y=e[i].v;
 78             if(y==1)    continue;
 79             if(p[y].d>x.d+e[i].l)
 80                 p[y].d=x.d+e[i].l;
 81                 q.push(p[y]);
 82             
 83         
 84     
 85     for(int i=2;i<=n;i++)
 86         if(i!=now)    de[i]=min(de[i],d[now]+p[i].d);
 87 
 88 int main()
 89 
 90     t=read();
 91     while(t--)
 92     
 93         clean();n=read();m=read();
 94         for(int i=1;i<=m;i++)
 95             int x=read(),y=read(),z=read();
 96             in[x]++;in[y]++;add(x,y,z);add(y,x,z);
 97         
 98         if(!dfs(1,0))
 99             printf("-1\n");
100             continue;
101         
102         for(int i=1;i<=n;i++)
103             d[i]=inf;
104             p[i].id=i;
105         
106         for(int i=fi[1];i!=0;i=e[i].ne)
107             int y=e[i].v;
108             d[y]=e[i].l;
109             Dij(y);
110         
111         int ans=inf;
112         for(int i=2;i<=n;i++)    ans=min(ans,d[i]+de[i]);
113         printf("%d\n",ans);
114     
115     return 0;
116 
View Code

 

以上是关于单身三连之二的主要内容,如果未能解决你的问题,请参考以下文章

经典算法题在数组中找两个单身狗

单身人口,超过2亿

phpwamp单身狗模式的详解与分析,单身狗模式/即霸体模式的作用讲解。

phpwamp单身狗模式的详解与分析,单身狗模式/即霸体模式的作用讲解。

数组找出单身狗经典问题

1065. 单身狗(25)