出题人的英文太优秀了,题目好像什么都没说一样。看了别人的博客才明白,别人猜题意能力还是比我厉害太多了。题目也是错的。
题意归结为(我还是不是很懂,用自己语言描述下):假设有一栋楼,有n层,相邻两层之间的移动的花费为c。然后又有n个节点,他们分别在li层。然后有m条特殊的路径,每条路经上u,v两点之间可以相互传送,花费为w。求节点1到节点n的最小花费。
坑点1:如果两个节点在同一层,他们之间没有路径的话,他们是不相连的。这就是为什么会有-1的情况了。
坑点2:尽管同一层的点是不相连的,但是他们都可以从该楼层到相邻楼层,花费为c。
如果才能处理这种关系,参考了别人的做法,我是直接将每个楼层都拆成两个点,一入一出。这样就不会有同一楼层的节点到达同一楼层另外节点花费为0了。
这种拆点还是很经典的,就是这个,可能是西班牙人出的题目,十分迷。
还有就是,我这种做法的话,用spfa会tle,然后改成dijkstra就过了,但是也跑了500ms+。时限才1s。
代码如下:
#include<iostream>
#include<cstdio>
#include<vector>
#include<queue>
#include<utility>
#include<stack>
#include<algorithm>
#include<cstring>
#include<string>
#include<cmath>
using namespace std;
typedef pair<int, int> pii;
const int maxn = 3e5 + 10;
const int maxm = 6e5 + 10;
const int INF = 0x7fffffff;
int n, m;
vector <int> layer[maxn];
int head[maxn], nx[maxm], cost[maxm], to[maxm], ppp = 0;
void add_edge(int u, int v, int c) {
to[ppp] = v, nx[ppp] = head[u], cost[ppp] = c, head[u] = ppp++;
}
int dis[maxn];
bool flag[maxn];
void spfa(int s) {
int u, v;
fill(dis, dis + 3 * n + 10, INF);
memset(flag, 0, sizeof(flag));
dis[s] = 0;
queue <int> q;
q.push(s);
while(!q.empty()) {
u = q.front();
q.pop();
flag[u] = 0;
for(int i = head[u]; ~i; i = nx[i]) {
v = to[i];
if(dis[v] > dis[u] + cost[i]) {
dis[v] = dis[u] + cost[i];
if(!flag[v]) {
flag[v] = 1;
q.push(v);
}
}
}
}
}
void dijkstra(int s, int e) {
fill(dis, dis + 3 * n + 5, INF);
priority_queue<pii, vector<pii>, greater<pii> >q;
dis[s] = 0;
q.push(pii(0, s));
pii tmp;
int u, v;
while(!q.empty()) {
tmp = q.top();
q.pop();
int u = tmp.second;
if(tmp.first > dis[u])
continue;
if(u == e)
return;
for(int i = head[u]; ~i; i = nx[i]) {
v = to[i];
if(dis[v] > dis[u] + cost[i]) {
dis[v] = dis[u] + cost[i];
q.push(pii(dis[v], v));
}
}
}
}
int main() {
#ifndef ONLINE_JUDGE
freopen("in.txt", "r", stdin);
// freopen("out.txt", "w", stdout);
#endif
int T, Case = 1;
int u, v, c;
cin >> T;
while(T--) {
memset(head, -1, sizeof(head));
ppp = 0;
scanf("%d%d%d", &n, &m, &c);
for(int i = 1; i + 1 <= n; i++) {
add_edge(2 * i, 2 * (i + 1) - 1, c);
add_edge(2 * (i + 1), 2 * i - 1, c);
}
int s = 2 * n;
for(int i = 1; i <= n; i++) {
scanf("%d", &u);
layer[u].push_back(s + i);
}
for(int i = 1; i <= n; i++) {
for(int j = 0; j < layer[i].size(); j++) {
add_edge(layer[i][j], 2 * i, 0);
add_edge(2 * i - 1, layer[i][j], 0);
}
}
while(m--) {
scanf("%d%d%d", &u, &v, &c);
add_edge(s + u, s + v, c);
add_edge(s + v, s + u, c);
}
// spfa(s + 1);
dijkstra(s + 1, s + n);
if(dis[s + n] == INF)
printf("Case #%d: -1\n", Case++);
else
printf("Case #%d: %d\n", Case++, dis[s + n]);
for(int i = 1; i <= n; i++)
layer[i].clear();
}
return 0;
}