码迷,mamicode.com
首页 > 其他好文 > 详细

单身三连之二

时间:2019-07-21 13:31:14      阅读:63      评论:0      收藏:0      [点我收藏+]

标签:for   int   getc   closed   ++   dijkstra   getchar   end   开始   

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

题目大意:

  有一张无向图,求经过起点的最小环。(点数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

 

单身三连之二

标签:for   int   getc   closed   ++   dijkstra   getchar   end   开始   

原文地址:https://www.cnblogs.com/hz-Rockstar/p/11220112.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!