题意:每个点放在一层,然后给了n个点,n层楼(一楼可多点),相邻的两层距离是固定的k,有额外m条边,然后求1到n的最短路径,如果没有则输出-1
重要的还是建图吧。
每一层拆出来一个出点一个入点,从n+1~2n,从2n+1~3n,相邻层出连入权值为k;点在哪一层就:入~点~出。
1~n就表示1~n这些点。
时间卡的很恶心啊,spfa 998ms卡过一个其他的都是一样的代码都没过。。。。。。看网上用什么双端队列。。。
dijkstra这个地方还是好点两次都稳过,大概点和边都太多了吧。。。
链接:hdu 4725
#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <string>
#include <set>
#include <map>
#include <stack>
#include <queue>
#define inf 0x3f3f3f3f
using namespace std;
const int maxn = 1000005;
int n = maxn, m, s, t; //n为点数 s为源点
int head[maxn]; //head[from]表示以head为出发点的邻接表表头在数组es中的位置,开始时所有元素初始化为-1
int d[maxn]; //储存到源节点的距离,在Spfa()中初始化
int cnt[maxn];
bool inq[maxn]; //这里inq作inqueue解释会更好,出于习惯使用了inq来命名,在Spfa()中初始化
int nodep; //在邻接表和指向表头的head数组中定位用的记录指针,开始时初始化为0
int pre[maxn];
int r[maxn];
struct node {
int v, w, next;
}es[maxn * 10];
void init() {
for(int i = 0; i <= n * 3 + 1; i++) {
d[i] = inf;
inq[i] = false;
cnt[i] = 0;
head[i] = -1;
pre[i] = -1;
r[i] = 0;
}
nodep = 0;
}
void addedge(int from, int to, int weight)
{
es[nodep].v = to;
es[nodep].w = weight;
es[nodep].next = head[from];
head[from] = nodep++;
}
bool spfa()
{
queue<int> que;
d[s] = 0; //s为源点
inq[s] = 1;
que.push(s);
while(!que.empty()) {
int u = que.front();
que.pop();
inq[u] = false; //从queue中退出
//遍历邻接表
for(int i = head[u]; i != -1; i = es[i].next) { //在es中,相同from出发指向的顶点为从head[from]开始的一项,逐项使用next寻找下去,直到找到第一个被输
//入的项,其next值为-1
int v = es[i].v;
if(d[v] > d[u] + es[i].w) { //松弛(RELAX)操作
d[v] = d[u] + es[i].w;
//pre[v] = u;
if(!inq[v]) { //若被搜索到的节点不在队列que中,则把to加入到队列中去
inq[v] = true;
que.push(v);
if(++cnt[v] > n * 3) {
return false;
}
}
}
}
}
return true;
}
void putpath() {
stack<int> path;
int now = t;
while(1) {
path.push(now);
if(now == s) {
break;
}
now = pre[now];
}
while(!path.empty()) {
now = path.top();
path.pop();
printf("%d\n", now);
}
}
int main()
{
int T, kcase = 0, k;
cin >> T;
while(T--) {
printf("Case #%d: ", ++kcase);
cin >> n >> m >> k;
init();
for(int i = 1; i <= n; i++) {
if(i == 1) {
addedge(i + n * 2, i + 1 + n, k);
}
else if(i == n) {
addedge(i + n * 2, i - 1 + n, k);
}
else {
addedge(i + n * 2, i + 1 + n, k);
addedge(i + n * 2, i - 1 + n, k);
}
}
int a;
for(int i = 1; i <= n; i++) {
scanf("%d", &a);
addedge(a + n, i, 0);
addedge(i, a + n * 2, 0);
}
int b, c;
while(m--) {
scanf("%d %d %d", &a, &b, &c);
addedge(a, b, c);
addedge(b, a, c);
}
s = 1;
if(spfa()) {
if(d[n] == inf) {
puts("-1");
}
else {
cout << d[n] << endl;
}
}
}
return 0;
}
#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <string>
#include <set>
#include <map>
#include <stack>
#include <queue>
#define inf 0x3f3f3f3f
using namespace std;
const int maxn = 1000005;
const int maxm = 10050000;
int n = maxn, m, s, t; //n为点数 s为源点
int head[maxn]; //head[from]表示以head为出发点的邻接表表头在数组es中的位置,开始时所有元素初始化为-1
int d[maxn]; //储存到源节点的距离,在init()中初始化
bool vis[maxn]; //是否访问过
int nodep; //在邻接表和指向表头的head数组中定位用的记录指针,开始时初始化为0
int pre[maxn];
struct node {
int num;
int dis;
node (int a = 0, int b = 0) : num(a), dis(b) {}
friend bool operator <(node a, node b) {
return a.dis > b.dis;
}
};
struct edge {
int v, next;
int w;
}es[maxm];
void init() {
for(int i = 0; i < maxn; i++) {
d[i] = inf;
vis[i] = false;
head[i] = -1;
pre[i] = -1;
}
nodep = 0;
}
void addedge(int from, int to, int weight)
{
es[nodep].v = to;
es[nodep].w = weight;
es[nodep].next = head[from];
head[from] = nodep++;
}
void dijkstra()
{
priority_queue<node> pq;
d[s] = 0; //s为源点
pq.push(node(s, 0));
while(!pq.empty()) {
node num = pq.top();
pq.pop();
int u = num.num;
if(vis[u]) continue;
vis[u] = 1;
//遍历邻接表
for(int i = head[u]; i != -1; i = es[i].next) { //在es中,相同from出发指向的顶点为从head[from]开始的一项,逐项使用next寻找下去,直到找到第一个被输
//入的项,其next值为-1
int v = es[i].v;
if(!vis[v] && d[v] > d[u] + es[i].w) { //松弛(RELAX)操作
d[v] = d[u] + es[i].w;
pre[v] = u;
pq.push(node(v, d[v]));
}
}
}
}
void putpath() {
stack<int> path;
int now = t;
while(1) {
path.push(now);
if(now == s) {
break;
}
now = pre[now];
}
while(!path.empty()) {
now = path.top();
path.pop();
printf("%d\n", now);
}
}
int main()
{
int T, kcase = 0, k;
cin >> T;
while(T--) {
printf("Case #%d: ", ++kcase);
cin >> n >> m >> k;
init();
for(int i = 1; i <= n; i++) {
if(i == 1) {
addedge(i + n * 2, i + 1 + n, k);
}
else if(i == n) {
addedge(i + n * 2, i - 1 + n, k);
}
else {
addedge(i + n * 2, i + 1 + n, k);
addedge(i + n * 2, i - 1 + n, k);
}
}
int a;
for(int i = 1; i <= n; i++) {
scanf("%d", &a);
addedge(a + n, i, 0);
addedge(i, a + n * 2, 0);
}
int b, c;
while(m--) {
scanf("%d %d %d", &a, &b, &c);
addedge(a, b, c);
addedge(b, a, c);
}
s = 1;
dijkstra();
if(d[n] == inf) {
puts("-1");
}
else {
cout << d[n] << endl;
}
}
return 0;
}