Poj 3159(差分制約システム、SPFA+スタック、Dij+heap)
最初の差分制約システムの問題をした後、熱いうちに鉄を打ってからもう一つ来ます.この問題が純粋な短距離問題カード時間の問題だとは思わなかった.問題の意味を理解するには注意すべき点があり、私は最初はSPFA(1)、dis[n]、再SPFA(n)、dis[1]を得て、両者の大きな値を取った.実際には前者だけでよいが,dis[n]は答えである.
1. 最初はSPFAのキュー実装を直接書いたばかりで、タイムアウトに違いない.
2. スタックがSPFAを実現するのが早いと聞いて、またスタックに書き換えたが、結局タイムアウトした.これはおかしい.discussはスタックが通れると言っているだろう.私は標準的な図の隣接テーブルストレージ、つまりチェーンテーブルで実現していますが、他の人が使っている配列でシミュレーションしているのを見て、配列シミュレーションが速いのではないかと思います.また変わったのか、悲劇がタイムアウトしたのか.
3. また、私のコードは他の人とは少し違うことに気づきました.私が追加した辺はadd(b,a,k)で、人はadd(a,b,k)ですが、影響はないと思います.一つの意味です.私はadd(a,b,k)に変更してAC(500+MS)にしました.
4. 逆に私の元の標準図の隣接テーブルストレージに変更して、またタイムアウトしました.これはちょっと納得できませんが、ポインタの操作の効率が高いと言っているのではないでしょうか.どうしてこれが体現できないのか、ましてこの時間の上限は1.5 Sで、配列シミュレーションで0.5 Sで、チェーンテーブルでタイムアウトします....本当に納得できない.
5. discussでは「点が少なくて辺が多く、Dijを使うべきだ」という問題がありますが、普通のDij時間の複雑さは(n^2)肯定タイムアウトなので、「優先キュー」でサイクルごとに最小のdis[i]値を探す過程を実現するには、c++のSTLのpriority_queue.悲劇的なのは私がc.なので、自分で優先列を実現するために山を書かなければなりません.長い間研究して,書き上げた.悲劇は直接だ
6. 葛藤.....葛藤する......バグを探して...探してる...探して...やっとc言語の同胞を見つけた.コードを分析してみると確かに発見しにくい脆弱性がある:最近の点、すなわち小根スタック中のルートQ[1]を見つけるたびに、変更点をキューから削除し、このとき新しいスタック、すなわちHeapAdjust(1)と、(この過程で私のプログラムは問題ありません)、この点に隣接する点を緩和して、緩和した後にdis[]が変化して、再びスタックを更新しなければなりません(これは私が落としました).....バグand AC(600+MS)を修正する.oh...yes...
7. この問題はまた30以上のSubmitに貢献しました...
マイSPFA(スタック実装):
私のDij+heap:
1. 最初はSPFAのキュー実装を直接書いたばかりで、タイムアウトに違いない.
2. スタックがSPFAを実現するのが早いと聞いて、またスタックに書き換えたが、結局タイムアウトした.これはおかしい.discussはスタックが通れると言っているだろう.私は標準的な図の隣接テーブルストレージ、つまりチェーンテーブルで実現していますが、他の人が使っている配列でシミュレーションしているのを見て、配列シミュレーションが速いのではないかと思います.また変わったのか、悲劇がタイムアウトしたのか.
3. また、私のコードは他の人とは少し違うことに気づきました.私が追加した辺はadd(b,a,k)で、人はadd(a,b,k)ですが、影響はないと思います.一つの意味です.私はadd(a,b,k)に変更してAC(500+MS)にしました.
4. 逆に私の元の標準図の隣接テーブルストレージに変更して、またタイムアウトしました.これはちょっと納得できませんが、ポインタの操作の効率が高いと言っているのではないでしょうか.どうしてこれが体現できないのか、ましてこの時間の上限は1.5 Sで、配列シミュレーションで0.5 Sで、チェーンテーブルでタイムアウトします....本当に納得できない.
5. discussでは「点が少なくて辺が多く、Dijを使うべきだ」という問題がありますが、普通のDij時間の複雑さは(n^2)肯定タイムアウトなので、「優先キュー」でサイクルごとに最小のdis[i]値を探す過程を実現するには、c++のSTLのpriority_queue.悲劇的なのは私がc.なので、自分で優先列を実現するために山を書かなければなりません.長い間研究して,書き上げた.悲劇は直接だ
6. 葛藤.....葛藤する......バグを探して...探してる...探して...やっとc言語の同胞を見つけた.コードを分析してみると確かに発見しにくい脆弱性がある:最近の点、すなわち小根スタック中のルートQ[1]を見つけるたびに、変更点をキューから削除し、このとき新しいスタック、すなわちHeapAdjust(1)と、(この過程で私のプログラムは問題ありません)、この点に隣接する点を緩和して、緩和した後にdis[]が変化して、再びスタックを更新しなければなりません(これは私が落としました).....バグand AC(600+MS)を修正する.oh...yes...
7. この問題はまた30以上のSubmitに貢献しました...
マイSPFA(スタック実装):
#include <stdio.h>
#include <stdlib.h>
#define INF 100000000
struct Edge
{
int e, v;
} edge[150005];
int neg;
int node[30005];
int next[150005];
int n;
int dis[30005], vst[30005];
int Q[30005];
void add(int s, int e, int v)
{
edge[neg].e = e;
edge[neg].v = v;
next[neg] = node[s];
node[s] = neg++;
}
int relax(int s, int e, int v)
{
if (dis[s]+v < dis[e])
{
dis[e] = dis[s]+v;
return 1;
}
return 0;
}
/* */
int SPFA(int s0)
{
int i, t, p, top;
for (i=1; i<=n; i++)
dis[i] = INF;
dis[s0] = 0;
Q[0] = s0;
top = 1;
vst[s0] = 1;
while (top)
{
t = Q[--top];
p = node[t];
while (p != -1)
{
if (relax(t, edge[p].e, edge[p].v) && !vst[edge[p].e])
{
Q[top++] = edge[p].e;
vst[edge[p].e] = 1;
}
p = next[p];
}
vst[t] = 0;
}
return 1;
}
int main()
{
int m, k, a, b;
memset(node, -1, sizeof(node));
scanf("%d %d", &n, &m);
while (m--)
{
scanf("%d %d %d", &a, &b, &k);
add(a, b, k);
}
SPFA(1);
printf("%d/n", dis[n]);
}
私のDij+heap:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define MAXV 30005
#define MAXE 150005
#define INF 1000000000
struct Edge
{
int e, v;
} edge[MAXE];
int n, neg;
int dis[MAXV], vst[MAXV];
int node[MAXV], next[MAXE];
int Q[MAXV];
int index[MAXV];
void add(int s, int e, int v)
{
edge[neg].e = e;
edge[neg].v = v;
next[neg] = node[s];
node[s] = neg++;
}
void swap(int x, int y)
{
int t;
t = Q[x];
Q[x] = Q[y];
Q[y] = t;
index[Q[x]] = x;
index[Q[y]] = y;
}
void heapAdjust(int root)
{
int l, r, min;
l = 2*root;
r = 2*root+1;
min = root;
if (l <= Q[0] && dis[Q[l]] < dis[Q[min]])
min = l;
if (r <= Q[0] && dis[Q[r]] < dis[Q[min]])
min = r;
if (min != root)
{
swap(root, min);
heapAdjust(min);
}
}
void buildHeap()
{
int i;
Q[0] = n;
for (i=1; i<=n; i++)
{
Q[i] = i;
index[i] = i;
}
for (i=n/2; i>=1; i--)
heapAdjust(i);
}
/* dis[Q[root]] , , Q[root] */
void update(int root)
{
while (root/2 && dis[Q[root]] < dis[Q[root/2]])
{
swap(root, root/2);
root = root/2;
}
}
int getMin()
{
int min;
min = Q[1];
Q[1] = Q[Q[0]];
Q[0]--;
index[Q[1]] = 1;
heapAdjust(1);
return min;
}
/* Dijkstra , */
void Dijkstra(int s0)
{
int i, k, p;
for (i=1; i<=n; i++)
dis[i] = INF;
dis[s0] = 0;
buildHeap();
while (Q[0])
{
k = getMin();
vst[k] = 1;
p = node[k];
while (p != -1)
{
if (!vst[edge[p].e] && dis[k]+edge[p].v<dis[edge[p].e])
{
dis[edge[p].e] = dis[k]+edge[p].v;
update(index[edge[p].e]);
/* index , dis[e], ,
, e ,
dis[e] . */
}
p = next[p];
}
}
}
int main()
{
int m, k, a, b;
memset(node, -1, sizeof(node));
scanf("%d %d", &n, &m);
while (m--)
{
scanf("%d %d %d", &a, &b, &k);
add(a, b, k);
}
Dijkstra(1);
printf("%d/n", dis[n]);
return 0;
}