Spoj有一个名为HIGHWAYS的问题,基本上是找到两个城市之间的最短路径。
我第一次解决它时,我使用了Dijkstra算法......我说得对,虽然代码有点大,所以我决定用更小的代码重做它(显然行为方式相同),但它是超时限制。
我想知道他们之间有什么区别才能让这个TLE发生。
输入如下:
n //number of test cases
c e s e //number of cities (from 1 to c), number of edges, start and end cities
c1 c2 w //e lines, each with connection between c1 and c2 with weight w
以下是长码(已接受):
#include <bits/stdc++.h>
using namespace std;
#define si(n) scanf("%d", &n)
#define INF 99999
int d[100010];
struct edge {
int v, weight;
edge(int a, int w) {
v = a;
weight = w;
}
bool operator < (const edge & o) const {
return weight > o.weight;
}
};
struct vertex {
int value;
vector <edge> adj;
vertex() {
adj.clear();
}
vertex(int val) {
value = val;
adj.clear();
}
void add(edge a) {
adj.push_back(a);
}
};
struct graph {
vertex v[100010];
void add_v(int val) {
vertex a(val);
a.adj.clear();
v[val] = a;
}
void add_a(int v1, int v2, int p) {
v[v1].add(edge(v2, p));
v[v2].add(edge(v1, p));
}
void dijkstra(int n, int f) {
for(int i = 0; i <= f; i++ ) d[i] = INF;
priority_queue < edge > Q;
d[n] = 0;
int current;
Q.push(edge(n, 0));
while (!Q.empty()) {
current = Q.top().v;
Q.pop();
for (int i = 0; i < v[current].adj.size(); i++) {
edge a = v[current].adj[i];
if (d[a.v] > d[current] + a.weight) {
d[a.v] = d[current] + a.weight;
Q.push(edge(a.v, d[a.v]));
}
}
}
}
};
int main(){
int cases;
si(cases);
int v, a, ini, fim;
int v1, v2, w;
while(cases--){
si(v); si(a);
si(ini); si(fim);
graph g;
for(int i = 1; i <= v; i++){
g.add_v(i);
}
for(int i = 0; i < a; i++){
si(v1); si(v2); si(w);
g.add_a(v1, v2, w);
}
g.dijkstra(ini, v+1);
int dist = d[fim];
if(dist < 0 || dist >= INF) printf("NONE\n");
else printf("%d\n", dist);
}
}
这是短篇(超出时间限制):
#include <bits/stdc++.h>
using namespace std;
struct edge{
int v, w;
edge(){}
edge(int a, int b){v = a; w = b;}
};
bool operator < (edge a, edge b) {return a.w < b.w;}
const int INF = INT_MAX;
typedef vector<vector<edge> > graph;
typedef priority_queue<edge> heap;
int d[100020];
void Dijkstra(graph G, int length, int s){
for(int i = 1; i <= length; i++) d[i] = INF;
edge base;
base.v = s;
base.w = d[s] = 0;
heap H;
H.push(base);
while(!H.empty()){
int current = H.top().v;
H.pop();
for (int i = 0; i < G[current].size(); i++) {
edge a = G[current][i];
if (d[a.v] > d[current] + a.w) {
d[a.v] = d[current] + a.w;
H.push(edge (a.v, d[a.v]));
}
}
}
}
int main(){
int cases;
int n, m, s, e;
int v1, v2, w;
scanf("%d", &cases);
while(cases--){
scanf("%d %d %d %d", &n, &m, &s, &e);
graph G(n + 1);
for(int i = 0; i < m; i++){
scanf("%d %d %d", &v1, &v2, &w);
G[v1].push_back(edge(v2, w));
G[v2].push_back(edge(v1, w));
}
Dijkstra(G, n, s);
if(d[e] != INF) printf("%d\n", d[e]);
else printf("NONE\n");
}
}
答案 0 :(得分:1)
不同之处在于您如何控制优先级队列。在长版本中,您首先使用较小的重量边缘,这使您能够更早地找到最佳路径并缩短许多可能的路径:
bool operator < (const edge & o) const {
return weight > o.weight;
}
在短版本中,您的行为(意外地?)反转并始终采用最大权重的边缘,这意味着您可以有效地探测所有可能的路径。
bool operator < (edge a, edge b) {return a.w < b.w;}
更改不等式运算符,两个版本的运行速度相同。
答案 1 :(得分:0)
STL的容器很慢。如有必要,请避免使用矢量。
这是我的dij:
class graph
{
public :
int head[N],next[M],node[M];
int dist[M];
int tot;
void init()
{
tot = 0;
CLR(head,-1);
}
void add(int x,int y,int z = 1)
{
node[tot] = y;
dist[tot] = z;
next[tot] = head[x];
head[x] = tot++;
}
graph() {init();}
} g;
int dist[N]; ///the distance
///src means source. ter is optional, it means terminal
void dij(int src, graph &g, int ter=-1)
{
memset(dist,0x3f,sizeof(dist)); ///init d[i] as a very large value
dist[src] = 0;
priority_queue<pair<int,int>,vector<pair<int,int> >,greater<pair<int,int> > > pq;
pq.push(make_pair(dist[src],src));
while(!pq.empty())
{
int x = pq.top().second;
int d = pq.top().first;
if(d != dist[x])continue;
if(x == ter)return ;
for(int i = g.head[x] ; ~i ; i = g.next[i])
{
int y = g.node[i];
if(d+g.dist[i]<dist[y])
{
dist[y] = d + g.dist[i];
pq.push(make_pair(dist[y],y));
}
}
}
}