题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4725
十万个点 如果相邻层的点都各自建边的话 有可能就变成50000×50000条边 时间空间都爆了
这里一个处理手法是 借鉴网络流的出点和入点的思想 把每一层抽象出一个出点和入点(注意不能让同层的点无代价互通)
其中一种具体做法是
把入点往该层的所有点连一条代价为0的单向边 把该层所有点往出点连一条代价为0的单向边
把出点往相邻层的入点连一条代价为C的单向边
其他的正常建边
注意 入点不能连到同层的出点
我用的是dijkstra + heap
不过应该存在很多可以优化的地方
网上也有不拆点的做法可以减少边数 但是每层抽象出一个或几个点的做法是没错的
#include <cstdio> #include <cstdlib> #include <ctime> #include <iostream> #include <cmath> #include <cstring> #include <algorithm> #include <stack> #include <set> #include <queue> #include <vector> using namespace std; typedef long long ll; typedef unsigned long long ull; typedef pair<int, int> P; const int maxv = 510000; const int maxe = 1000000; const int INF = 0x3fffffff; struct edge { int to, cost, next; }E[maxe]; int head[maxv]; int d[maxv]; int si; priority_queue<P, vector<P>, greater<P> > que; void addedge(int u, int v, int cost) { E[si].to = v; E[si].cost = cost; E[si].next = head[u]; head[u] = si++; } int main() { //freopen("in.txt", "r", stdin); int T; scanf("%d", &T); int n, m, c, V; for(int t = 1; t <= T; t++) { memset(E, -1, sizeof(E)); memset(head, -1, sizeof(head)); si = 0; scanf("%d%d%d", &n, &m, &c); V = 3*n; for(int i = 1; i <= n; i++) { int layer; scanf("%d", &layer); addedge(i, n + 2*layer, 0);//out addedge(n + 2*layer - 1, i, 0);//in } for(int i = 1; i < n; i++) { addedge(n + 2*i, n + 2*(i+1) - 1, c); addedge(n + 2*(i+1), n + 2*i - 1, c); } for(int i = 0; i < m; i++) { int u, v, cost; scanf("%d%d%d", &u, &v, &cost); addedge(u, v, cost); addedge(v, u, cost); } fill(d, d + V + 10, INF); d[1] = 0; que.push(P(0, 1)); while(!que.empty()) { P p = que.top(); que.pop(); int v = p.second; if(d[v] < p.first) continue; for(int i = head[v]; i != -1; i = E[i].next) { edge e = E[i]; if(d[e.to] > d[v] + e.cost) { d[e.to] = d[v] + e.cost; que.push(P(d[e.to], e.to)); } } } printf("Case #%d: ", t); if(d[n] == INF) printf("-1 "); else printf("%d ", d[n]); } return 0; }