2069: [POI2004]ZAW
Posted mjtcn
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了2069: [POI2004]ZAW相关的知识,希望对你有一定的参考价值。
2069: [POI2004]ZAW
题意:
给定一张带权图(边是双向的,但不同方向长度不同)。求从1出发,至少经过除1外的一个点,再回到1的最短路。点和边不能重复经过。 n≤5000,m≤10000
分析:
因为不能重复经过,不能直接最短路的,考虑去掉不能重复经过一个点的限制。
可以枚举所有与1有边的点,然后从这里面枚举一个点的,求出到其他与1相连的点最短路,来更新。
这样显然复杂度是关于1的出度的,复杂度并不是很理想。
然后这里有一个技巧,按照二进制某一位上的01分成两个集合,然后跑多源最短路。
为什么可以呢?任何两个不同的点的二进制位最少存在一位不同。
复杂度$O(nlog^2n)$
代码:
#include<cstdio> #include<algorithm> #include<cstring> #include<iostream> #include<cmath> #include<cctype> #include<set> #include<queue> #include<vector> #include<map> #define pa pair<int,int> using namespace std; typedef long long LL; inline int read() { int x=0,f=1;char ch=getchar();for(;!isdigit(ch);ch=getchar())if(ch==‘-‘)f=-1; for(;isdigit(ch);ch=getchar())x=x*10+ch-‘0‘;return x*f; } const int N = 20005, INF = 1e9; struct Edge{ int to, nxt, w; } e[50005]; int head[N], dis[N], df[N], dt[N], A[N], En; bool vis[N]; priority_queue< pa, vector< pa >, greater< pa > > q; inline void add_edge(int u,int v,int w) { ++En; e[En].to = v, e[En].nxt = head[u], e[En].w = w; head[u] = En; } void Dijkstra() { while (!q.empty()) { int u = q.top().second; q.pop(); if (vis[u]) continue; vis[u] = 1; for (int i = head[u]; i; i = e[i].nxt) { int v = e[i].to; if (dis[v] > dis[u] + e[i].w) { dis[v] = dis[u] + e[i].w; q.push(pa(dis[v], v)); } } } } int main() { int n = read(), m = read(), cnt = 0; for (int i = 1; i <= m; ++i) { int u = read(), v = read(), w; if (u == 1) { df[v] = read(), dt[v] = read(); if (!vis[v]) vis[v] = 1, A[++cnt] = v; } else if (v == 1) { dt[u] = read(), df[u] = read(); if (!vis[u]) vis[u] = 1, A[++cnt] = u; } else { w = read();add_edge(u, v, w); w = read();add_edge(v, u, w); } } int ans = INF; for (int k = 1; k <= cnt; k <<= 1) { for (int i = 1; i <= n; ++i) dis[i] = INF, vis[i] = 0; for (int i = 1; i <= cnt; ++i) if (i & k) q.push(pa(dis[A[i]] = df[A[i]], A[i])); Dijkstra(); for (int i = 1; i <= cnt; ++i) if (!(i & k)) ans = min(ans, dis[A[i]] + dt[A[i]]); for (int i = 1; i <= n; ++i) dis[i] = INF, vis[i] = 0; for (int i = 1; i <= cnt; ++i) if (!(i & k)) q.push(pa(dis[A[i]] = df[A[i]], A[i])); Dijkstra(); for (int i = 1; i <= cnt; ++i) if (i & k) ans = min(ans, dis[A[i]] + dt[A[i]]); } cout << ans; return 0; }
以上是关于2069: [POI2004]ZAW的主要内容,如果未能解决你的问题,请参考以下文章