大家都很强, 我还是算了吧。
我是智障
我是智障
我是智障
重要的事情说三遍, Woc!
我是智障
不行我还要再说一遍!
我把g_[]数组大小开成了MAXN, 只有一个点。TMD也不RE,就是WA。
Description
探险家小T好高兴!X国要举办一次溶洞探险比赛,获奖者将得到丰厚奖品哦!小T虽然对奖品不感兴趣,但是这个大振名声的机会当然不能错过!
比赛即将开始,工作人员说明了这次比赛的规则:每个溶洞和其他某些溶洞有暗道相连。两个溶洞之间可能有多条道路,也有可能没有,但没有一条暗道直接从自己连到自己。参赛者需要统一从一个大溶洞出发,并再次回到这个大溶洞。
如果就这么点限制,那么问题就太简单了,可是举办方又提出了一个条件:不能经过同一条暗道两次。这个条件让大家犯难了。这该怎么办呢?
到了大溶洞口后,小T愉悦地发现这个地方他曾经来过,他还记得有哪些暗道,以及通过每条暗道的时间。小T现在向你求助,你能帮他算出至少要多少时间才能回到大溶洞吗?
Input
第一行两个数n,m表示溶洞的数量以及暗道的数量。
接下来m行,每行4个数s、t、w、v,表示一个暗道连接的两个溶洞s、t,这条暗道正着走(s à t)的所需要的时间w,倒着走(t à s)所需要的时间v。由于溶洞的相对位置不同,w与v可能不同。
Output
输出一行一个数t,表示最少所需要的时间。
Sample Input
3 3
1 2 2 1
2 3 4 5
3 1 3 2
Sample Output
8
HINT
N<=10000,M<=200000,1<=W,V<=10000
不过能够想出最优的正确解法, 我也是很高兴的。但是WA了, 不开心啊不开心,郁闷。 大概思路如下:
先做一遍最短路,求出从S 到点i 的最短路中,第一个经过的点pre[i],即Sàpre[i]à….ài;若最短路为Sài,则pre[i]=i。求出pre后,重新构一遍图。令原图中点1 到i 的最短路为dist[i]。对于原图中的每一条边
(u,v,w):
1. 若u = S:
若v = pre[v],则略过;否则G’中连边(u,v,w);
2. 若v = S:
若u = pre[u],则G’中连边(u,T,w);否则连边(S,T,dist[u]+w);
3. 若u ≠ S 且v ≠ S:
若pre[u] = pre[v],则G’中连边(u,v,w);否则连边(S,v,dist[u]+w)。
这样在新图G’中求一遍S->T 的最短路即可。
这个构造很巧妙,它把每条S->i 的边拆开,这样就不会导致一条路走两遍(除形如S->i这种路外,其余的路没必要走)。构完图后,只需一遍最短路即可初解。
那么, 我的方法是虚拟一个点 n + 1,就可以把问题转化成由1 到 n + 1的最短路,SPFA会被卡, 但是某个神直接卡过常数, 强者, 他说, 要相信玄学!yoyoyo~
放代码
#include "queue"
#include "cstdio"
#include "cctype"
#include "cstdlib"
#include "cstring"
const int MOD = 1000000007;
#define abs(a) ((a) > 0 ? (a) : (-a))
#define max(a, b) ((a) > (b) ? (a) : (b))
#define min(a, b) ((a) < (b) ? (a) : (b))
#define rep(_, m, n) for(register int _ = (m); _ <= (n); ++_)
#define res(_, m, n) for(register int _ = (m); _ >= (n); --_)
#define edges(u) for(register int i = head[u]; i; i = g[i].pre)
template <class T>
inline bool readIn(T &x) {
T flag = 1; char ch;
while(!(isdigit(ch = (char) getchar())) && ch != -1) if( ch == '-' ) flag = -1;
if(ch == -1) return false;
for(x = ch - 48; isdigit(ch = (char) getchar()); x = (x << 1) + (x << 3) + ch - 48);
x *= flag;
return true;
}
template <class T>
inline void write(T x) {
if (x > 9)
write(x / 10);
putchar(x % 10 + 48);
}
template <class T>
inline bool writeIn(T x) {
if (x < 0) {
putchar('-');
x = -x;
}
write(x);
return true;
}
struct io {
#define SIM "exp"
io() {
freopen(SIM ".in", "r", stdin);
freopen(SIM ".out", "w", stdout);
}
~io() {
fclose(stdin);
fclose(stdout);
}
} WhiteBunny;
const int MAXN = 10005, MAXM = 400005;
int n, m, p[MAXN];
namespace S {
class edge {
public:
int to, pre, w;
edge(int to = 0, int pre = 0, int w = 0) : to(to), pre(pre), w(w) { }
} g[MAXM], g_[MAXM];//FUKKKKKKKKKKKKKKKKK!
int ne, head[MAXN], vis[MAXN], dis[MAXN], head_[MAXN];
inline bool adde(int u, int v, int w) {
g[++ne] = edge(v, head[u], w), head[u] = ne;
return true;
}
inline bool _adde(int u, int v, int w) {
g_[++ne] = edge(v, head_[u], w), head_[u] = ne;
return true;
}
class Dijkstra {
private:
struct nod {
int id, w;
nod(int id = 0, int w = 0) : id(id), w(w) { }
inline bool operator < (const nod &rhs) const {
return w > rhs.w;
}
};
std::priority_queue<nod> q;
public:
void dijkstra() {
memset(dis, 0x3f, sizeof (int) * (n + 3));
memset(vis, false, sizeof (int) * (n + 3));
q.push(nod(1, 0)); dis[1] = 0;
while( !q.empty() ) {
int u = q.top().id; q.pop();
if(vis[u]) continue;
vis[u] = true;
edges(u) {
int v = g[i].to;
if( dis[v] > dis[u] + g[i].w ) {
dis[v] = dis[u] + g[i].w;
q.push(nod(v, dis[v]));
!(u ^ 1) ? p[v] = v : p[v] = p[u];
}
}
}
}
} D;
}
using namespace S;
inline void rebuild_graph() {
ne = 0;
rep(u, 1, n) {
edges(u) {
int v = g[i].to;
if( v == 1 ) {
if(p[u] ^ u) _adde(1, n + 1, dis[u] + g[i].w);
else _adde(u, n + 1, g[i].w);
}
if( !(u ^ 1) && (p[v] ^ v) )
_adde(1, v, g[i].w);
if((v ^ 1) && (u ^ 1)) {
if(p[u] ^ p[v]) _adde(1, v, dis[u] + g[i].w);
else _adde(u, v, g[i].w);
}
}
}
rep(i, 1, n + 1) head[i] = head_[i];
rep(i, 1, ne) g[i] = g_[i];
}
inline void initialize() {
int s, t, v, w;
readIn(n);readIn(m);
rep(i, 1, m) readIn(s), readIn(t), readIn(v), readIn(w), adde(s, t, v), adde(t, s, w);
}
int main() {
initialize();
D.dijkstra();
rebuild_graph();
D.dijkstra();
writeIn(dis[n + 1]);
puts("");
return 0;
}