您的位置:首页 > 其它

PowerOj 2478 最短路问题 邻接表spfa

2016-03-26 00:50 288 查看


2478: 最短路问题

Time Limit:5000MS Memory Limit:65536KB

Total Submit:24 Accepted:4 Page
View:387

Submit Status Discuss


Description

现在有n个城市,编号从1到n。现在已知从城市i到城市j需要走的时间为aij。M78要从城市1到城市n。M78有一个飞行符,飞行符可以使得他瞬间通过一条边或连续的两条边(连续走一条边或两条边的时间为0)。问,M78从城市1到城市n,最少花费的时间。



Input

多组输入。每组第一行有一个整数n,表示城市的数目。(2<=n<=1000)
接下来将输入一个n*n的矩阵。矩阵第i行第j列的数字aij表示从城市i到城市j,花费的时间为aij。(0<=aij<=10000 , aii=0 ,aij=aji)。如果aij=0,表示没有这条路。



Output

每组输出一个数字,表示M78从城市1到城市n花费的最少时间。特别的,如果M78到不到了城市n,输出-1。


Sample
Input
Raw

3
0 1 1
1 0 1
1 1 0


Sample
Output
Raw

0




传送门:点击打开链接

首先用邻接表存图。

用spfa进行变形。这道题需要加三个状态,dis[maxn][3],2表示当前点未使用飞行符所以还可以多走两条边,1表示使用过飞行符一次,还可以对下一个点使用飞行符,0表示飞行符已被使用完毕,只能进行普通更新。

这样,对于某个点的状态为2,可以选择使用和不使用(即2->1或者2->2),两种状态都更新(2->1进行比较赋值,2->2就普通的更新),推进spfa的队列里面,对于状态1,利用贪心的思想,不用白不用,就这个点的下一个点必定使用飞行符。状态0的时候代表不能使用飞行符了,就进行普通的更新。

我开始有个疑问就是为什么飞行符能走2条边,怎么会只有使用一次,只有一条边,这种情况就使用起点和终点直接连接,所以直接使用一次就行了。

CODE
#include <stdio.h>
#include <iostream>
#include <algorithm>
#include <string.h>
#include <queue>

using namespace std;
const int maxn = 1000+10;
const int INF = 7e8;
struct Node ///邻接表的边
{
int to;
int len;
int next;
}e[maxn*maxn];

int n;
int top;
bool vis[maxn][3];  ///spfa的标记
int head[maxn];     ///头结点
int dis[maxn][3];   ///更新spfa最短路

void INIT()         ///初始化
{
top = 0;
for(int i = 0;i < maxn;i++)
{
head[i] = -1;
for(int j = 0;j < 3;j++)
dis[i][j] = INF,vis[i][j] = false;
}
}

void add(int u,int v,int len)  ///邻接表加边
{
e[top].to = v;
e[top].len = len;
e[top].next = head[u];
head[u] = top++;
}

struct node   ///spfa的起点有两个信息,当前点编号和状态
{
int id;
int flag;
};

void spfa()
{
dis[1][0] = dis[1][1] = dis[1][2] = 0;
vis[1][0] = vis[1][1] = vis[1][2] = true;
node st;
st.id = 1;
st.flag = 2;
queue<node> q;
q.push(st);
while(!q.empty())
{
st = q.front();
q.pop();
vis[st.id][st.flag] = false;
for(int i = head[st.id];i != -1;i = e[i].next)
{
node en;
en.id = e[i].to;
if(st.flag == 1)        ///状态1直接更新下一个点
{
if(dis[en.id][0] > dis[st.id][st.flag])
{
dis[en.id][0] = dis[st.id][st.flag];
en.flag = 0;
if(!vis[en.id][en.flag])
{
q.push(en);
vis[en.id][0] = true;
}
}
}
else if(st.flag == 2)   ///状态2有两种更新方式
{
if(dis[en.id][2] > dis[st.id][2]+e[i].len)  ///2->2,不使用飞行符
{
dis[en.id][2] = dis[st.id][2]+e[i].len;
if(!vis[en.id][2])
{
en.flag = st.flag;
q.push(en);
vis[en.id][2] = true;
}
}
if(dis[en.id][1] > dis[st.id][2])            ///2->1,使用飞行符
{
dis[en.id][1] = dis[st.id][2];
en.flag = st.flag-1;
if(!vis[en.id][en.flag])
{
q.push(en);
vis[en.id][en.flag] = true;
}
}
}
else///if(st.flag == 0)   状态0就进行普通更新
{
if(dis[en.id][0] > dis[st.id][0]+e[i].len)
{
dis[en.id][0] = dis[st.id][0]+e[i].len;
en.flag = 0;
if(!vis[en.id][0])
{
q.push(en);
vis[en.id][0] = true;
}
}
}
}
}
}

int main(void)
{
while(scanf("%d",&n) != EOF)
{
INIT();
for(int i = 1;i <= n;i++)
{
for(int j = 1;j <= n;j++)
{
int len;
scanf("%d",&len);
if(len != 0)
add(i,j,len);   ///学长指导下使用邻接表
}
}
spfa();
int ans = INF;
for(int i = 0;i < 3;i++)
{
if(ans > dis
[i])
ans = dis
[i];
}
if(ans == INF)
printf("-1\n");
else
printf("%d\n",ans);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: