一道正解不可靠,暴力碾标算的题。
题目大意:
有一张无向图,求经过起点的最小环。(点数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