acdream1415(dij+优先队列+桥)

这题好坑,卡SPFA。。。

无奈只能用dij+优先队列了。 因为好久没有写过代码了,所以今天写dij时候突然觉得复杂度不对,dij+优先队列的复杂度是(n+m)logn,这种复杂度对于稠密图是非常慢!,而且还有超内存的可能(最坏情况要把n*n个点都存进优先队列),与我以前记得复杂度是nlogn不一样。。。 瞬间吓尿。

其实事实确实是这样,在采用斐波那契堆+dij时,斐波那契堆是插入复杂度为O(1),所以复杂度为nlogn+m,而普通我们用的STL种的priority_queue插入查询复杂度都是logn,所以总的复杂度为(n+m)logn.

所以,dij+优先队列虽然方便好写,但只适用用稀疏图,也就是m小的时候。

最后关于这题的思路,求一次从1开始到其他所有点的最短距离diss[i],再求一次从n开始到其他所有点的最短距离dist[i],然后如果边 <u,v>w 满足diss[u]+w+dist[v]=min(其中min是1到n的最短距离)说明这条边,绝对在一条最短路线中。 这样把所有这样的边找出来,并重新构图,那么只要找出这个图中的桥,并且满足1,n分别在桥的两端。

Important Roads

Special JudgeTime Limit: 20000/10000MS (Java/Others)Memory Limit: 128000/64000KB (Java/Others)

SubmitStatisticNext Problem

Problem Description

The city where Georgie lives has n junctions some of which are connected by bidirectional roads.
      Every day Georgie drives from his home to work and back. But the roads in the city where Georgie lives are very bad, so they are very often closed for repair. Georgie noticed that when some roads are closed he still can get from home to work in the same time as if all roads were available.

But there are such roads that if they are closed for repair the time Georgie needs to get from home to work increases, and sometimes Georgie even cannot get to work by a car any more. Georgie calls such roads important.
      Help Georgie to find all important roads in the city.

Input

The first line of the input file contains n and m — the number of junctions and roads in the city where Georgie lives, respectively (2 ≤ n ≤ 20 000, 1 ≤ m ≤ 100 000). Georgie lives at the junction 1 and works at the junction n.

The following m lines contain information about roads. Each road is specified by the junctions it connects and the time Georgie needs to drive along it. The time to drive along the road is positive and doesn’t exceed 100 000. There can be several roads between a pair of junctions, but no road connects a junction to itself. It is guaranteed that if all roads are available, Georgie can get from home to work.

Output

Output l — the number of important roads — at the first line of the output file. The second line must contain l numbers, the numbers of important roads. Roads are numbered from 1 to m as they are given in the input file.

Sample Input

6 7
1 2 1
2 3 1
2 5 3
1 3 2
3 5 1
2 4 1
5 6 2

Sample Output

2
5 7

Source

Andrew Stankevich Contest 22

Manager

mathlover

  1 #include <iostream>
  2 #include <stdio.h>
  3 #include <string.h>
  4 #include <string>
  5 #include <algorithm>
  6 #include <stdlib.h>
  7 #include <queue>
  8 using namespace std;
  9 #define M 100100
 10 #define N 20020
 11 #define INF 0x3fffffffff
 12
 13 int n,m;
 14 struct node
 15 {
 16     int from,to,next,w,id;
 17 }edge[2*M];
 18
 19 struct node1
 20 {
 21     long long w;
 22     int id;
 23     bool operator < (const node1 t)const
 24     {
 25         return t.w<w;
 26     }
 27 };
 28
 29 int pre[N],cnt;
 30 long long int diss[N],dist[N];
 31 int que[M+10];//用循环队列怎么样
 32 int ans,save[M];
 33 //然后就是找桥了
 34
 35 priority_queue<node1> pque;
 36
 37 int len[N],mark[M];
 38 int index1;
 39
 40 void add_edge(int u,int v,int w,int id)
 41 {
 42     edge[cnt].from=u;
 43     edge[cnt].to=v;
 44     edge[cnt].w=w;
 45     edge[cnt].id=id;
 46     edge[cnt].next=pre[u];
 47     pre[u]=cnt++;
 48 }
 49
 50 void dij(long long int dis[N],int s)
 51 {
 52     memset(mark,0,sizeof(mark));
 53     while(pque.size()!=0) pque.pop();
 54
 55     for(int i=1;i<=n;i++)
 56         dis[i]=INF;
 57
 58     dis[s]=0;
 59     node1 fi;
 60     fi.id=s;
 61     fi.w=0;
 62     pque.push(fi);
 63     //我就说, 用优先队列优化,对于稠密图基本没意义
 64     node1 nwnode,cur;
 65     while(pque.size()!=0)
 66     {
 67         cur = pque.top();
 68         pque.pop();
 69         if(mark[cur.id]==1) continue;
 70         int u=cur.id;
 71         mark[u]=1;
 72         for(int p=pre[u];p!=-1;p=edge[p].next)
 73         {
 74             int v=edge[p].to;
 75             if(mark[v]==1) continue;
 76             if(dis[v]>cur.w+edge[p].w)
 77             {
 78                 dis[v]=cur.w+edge[p].w;
 79                 nwnode.id=v;
 80                 nwnode.w=dis[v];
 81                 pque.push(nwnode);
 82             }
 83         }
 84     }
 85 }
 86
 87 void spfa(long long int dis[N],int s,int t)
 88 {
 89     //SPFA都忘记怎么写了
 90     memset(mark,0,sizeof(mark));
 91     for(int i=1;i<=n;i++)
 92     {
 93         dis[i]=INF;
 94     }
 95
 96     int qf=0,qd=0;
 97     que[qf]=s;
 98     qf++;
 99
100     dis[s]=0;
101     mark[s]=1;
102
103     while(qf!=qd)//作为一个循环队列,
104     {
105         int cur=que[qd];
106         qd=(qd+1)%M;
107         mark[cur]=0;
108         for(int p=pre[cur];p!=-1;p=edge[p].next)
109         {
110             int v = edge[p].to;
111             if( dis[v]>dis[cur] + edge[p].w )
112             {
113                 dis[v]=dis[cur]+edge[p].w;
114                 if(mark[v]==0)
115                 {
116                     que[qf]=v;
117                     qf=(qf+1)%M;
118                     mark[v]=1;
119                 }
120             }
121         }
122     }
123 }
124
125
126 void dfs(int s)
127 {
128     //len[s]==-1表示没来过
129
130     len[s]=index1++;
131     int tmp = len[s];
132     for(int p=pre[s];p!=-1;p=edge[p].next)
133     {
134         int v=edge[p].to;
135         if( mark[edge[p].id]==1 ) continue;
136
137         if(len[v]==-1)
138         {
139             mark[edge[p].id]=1;//把这条边标记了
140             dfs(v);
141             tmp=min(tmp,len[v]);
142             if(len[v]>len[s])//这个就是桥
143             {
144                 if(len[n]!=-1)
145                 {
146                     if(len[1]<=len[s]&&len[n]>=len[v])
147                     {
148                         save[ans++]=edge[p].id;
149                     }
150                 }
151             }
152         }//无向图的桥怎么求。。。,忘光了。
153         else
154         {
155             tmp=min(tmp,len[v]);
156         }
157     }
158
159     len[s]=tmp;
160 }
161
162 int main()
163 {
164     scanf("%d%d",&n,&m);
165     cnt=0;
166     memset(pre,-1,sizeof(pre));
167
168     for(int i=1;i<=m;i++)
169     {
170         int x,y,w;
171         scanf("%d%d%d",&x,&y,&w);
172         add_edge(x,y,w,i);
173         add_edge(y,x,w,i);
174     }
175
176     //卡SPFA???
177     //去你妹的
178
179     //spfa(diss,1,n);
180     //spfa(dist,n,1);
181
182     dij(diss,1);
183     dij(dist,n);
184
185     long long int mi=diss[n]; //最短距离
186     int tcnt = cnt;
187
188     cnt=0;
189     memset(pre,-1,sizeof(pre));
190
191     for(int i=0;i<tcnt;i+=2)
192     {
193         int x,y,w,id;
194         x=edge[i].from;
195         y=edge[i].to;
196         w=edge[i].w;
197         id=edge[i].id;
198         if( diss[x]+dist[y]+w ==mi || dist[x] + diss[y]+w==mi )
199         {
200             add_edge(x,y,w,id);
201             add_edge(y,x,w,id);
202         }
203     }
204     //构建了一个由所有可能最短路边构成的图
205     memset(mark,0,sizeof(mark)); //感觉要用来记录边比较好
206     memset(len,-1,sizeof(len));
207     index1=0;
208     ans = 0;
209
210     dfs(1);
211      printf("%d\n",ans);
212      if(ans!=0)
213     {
214          for(int i=0;i<ans-1;i++)
215              printf("%d ",save[i]);
216         printf("%d\n",save[ans-1]);
217     }
218     return 0;
219 }
时间: 2024-08-27 10:56:37

acdream1415(dij+优先队列+桥)的相关文章

poj 3013 Big Christmas Tree (dij+优先队列优化 求最短路)

模板 题意:给你一个图,1总是为根,每个边有单位价值,每个点有权重. 每条边的价值 = sum(后继节点权重)*边的单位价值. 求树的最小价值,即构成一棵树的n-1条边的最小价值. 算法: 1.因为每个边的价值都要乘以后来访问的节点的权重,而走到后来访问的点必经过这条边. 实际上总价值就是  到每个点的最短路径*这个点的权重. 2.但是这个题 数据量真的太大了,50000个点,50000条边. 写普通的dij算法tle. 必须加优先队列优化- - 据说spfa也能过,但是spfa算法不稳定- -

最短路总结

最近过的最短路题目稍微总结一下,顺便写一下模板,最短路算法众多有floyd.dij.bell-man.spfa,速度最快就是dij+优先队列或者dij+堆排序,spfa理论上很快o(ke)但实际并不一定不过spfa传说中有一个很NB用处就是处理带负权回路. 邻接表VS邻接矩阵:根据写题经验,如果可以用矩阵那一定是首选,矩阵速度比表快而且题目出现多重边时矩阵很好解决. 今天不小心又遇见正向表与最短路图(HDU2433),感觉很兴奋哈,通宵刷题的感觉很好玩!遗憾的是hdu1385还没过,那是一题最短

hdu3986 spfa+枚举

这题让我第一次感受到了什么叫做在绝望中A题.这题我总共交了18次,TLE不知道几次,WA也不知道几次. 这题不能用dijkstra,用这个我一直超时(我没试过dij+优先队列优化,好像优先队列优化后可以过).. 用了我近一天的时间...... #include<stdio.h> #include<queue> #include<string.h> using namespace std; #define maxn 1002 #define INF 99999999 st

E-免费的飞机

题目链接:https://ac.nowcoder.com/acm/contest/699/E 题目意思:有n个飞机场,给你起点s,终点e,有m种带权的无向边飞机线路.有k个线路,可以从中选一个免费飞行.问是否使用免费飞机票,并输出最短路花费. 思路: 1.先建普通飞机线路,算出最短路.再每一条免费线路重新算一次最短路,再判断是否比之前小. spfa写法: #include<iostream> #include<algorithm> #include<cstdio> #i

poj3013 邻接表+优先队列+Dij

把我坑到死的题 开始开题以为是全图连通是的最小值 ,以为是最小生成树,然后敲了发现不是,看了下别人的题意,然后懂了: 然后发现数据大,要用邻接表就去学了一下邻接表,然后又去学了下优先队列优化的dij: 这坑爹的题目我交了10几遍,也不知道错在哪里:后来知道了maxint要#define Maxint 10000000000: 然后long int 是过不了的,改成long long才能过 ,真是呵呵啊: 1 #include<stdio.h> 2 #include<string.h>

bzoj 1579: [Usaco2009 Feb]Revamping Trails 道路升级 优先队列+dij

1579: [Usaco2009 Feb]Revamping Trails 道路升级 Time Limit: 10 Sec  Memory Limit: 64 MBSubmit: 1768  Solved: 481[Submit][Status][Discuss] Description 每天,农夫John需要经过一些道路去检查牛棚N里面的牛. 农场上有M(1<=M<=50,000)条双向泥土道路,编号为1..M. 道路i连接牛棚P1_i和P2_i (1 <= P1_i <= N;

优先队列优化dij算法通用模板

例题链接 分析:迪杰斯特拉算法的核心思想就是每次选择最短的距离,用这个最短距离来更新相邻顶点的最短距离,并且在更新完毕后这个最短距离不需要再考虑,而优先队列恰好契合迪杰斯特拉算法的要求,用来优化正合适 优化后的时间复杂度为O(E log V). 1 #include <bits/stdc++.h> 2 using namespace std; 3 const int inf=1<<30; 4 typedef long long ll; 5 const double pi=acos(

优先队列优化dij算法

之前已经弄过模板了,但那个复杂一点,这个就是裸的dij,用起来更方便 输入格式:n,m,s,d分别是点数,边数,起点,终点 之后m行,输入x,y,z分别是两点即权值 题目链接:https://www.luogu.org/problemnew/show/P1339 1 #include <bits/stdc++.h> 2 using namespace std; 3 const int inf=1<<30; 4 typedef long long ll; 5 typedef pair

In Touch (hdu 5361 优先队列的Dij + 并查集优化)

In Touch Time Limit: 8000/4000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others) Total Submission(s): 1109    Accepted Submission(s): 298 Problem Description There are n soda living in a straight line. soda are numbered by 1,2,-,n from