PowerOj 2478 最短路问题 邻接表spfa
2016-03-26 00:50
288 查看
2478: 最短路问题
Time Limit:5000MS Memory Limit:65536KBTotal 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; }
相关文章推荐
- ReactiveCocoa 学习心得 -- 3
- 仿招商银行加载loading效果
- iOS中关于UITableView下拉刷新控件UIRefreshController那点事
- ubuntu14.04_install_gitlab_platform
- 字符设备驱动基本框架
- Android——gridLayout(网格布局)
- HDOJ-----1787欧拉函数
- 理解CSS相对定位和固定定位
- php base64数据与图片的转换
- Educational Codeforces Round 10(B)排序,构造
- Python 基础 —— str
- HDOJ 2037 今年暑假不AC
- 图片滚动
- 闭包
- 《日暮农归》
- Andfix热修复框架原理及源码解析-下篇
- 新的Calculator的规范作业
- Educational Codeforces Round 10(A)模拟
- Windows下MongoDB安装与PHP扩展
- 匹配html中a标签的内容