原题链接:http://poj.org/problem?id=1847
我的链接:http://acm.hust.edu.cn/vjudge/contest/view.action?cid=19651#problem/D
最短路模板题。
Tram
Time Limit: 1000MS | Memory Limit: 30000K | |
Total Submissions: 7960 | Accepted: 2861 |
Description
Tram network in Zagreb consists of a number of intersections and rails connecting some of them. In every intersection there is a switch pointing to the one of the rails going out of the intersection. When the tram enters the intersection it can leave only in the direction the switch is pointing. If the driver wants to go some other way, he/she has to manually change the switch.
When a driver has do drive from intersection A to the intersection B he/she tries to choose the route that will minimize the number of times he/she will have to change the switches manually.
Write a program that will calculate the minimal number of switch changes necessary to travel from intersection A to intersection B.
Input
The first line of the input contains integers N, A and B, separated by a single blank character, 2 <= N <= 100, 1 <= A, B <= N, N is the number of intersections in the network, and intersections are numbered from 1 to N.
Each of the following N lines contain a sequence of integers separated by a single blank character. First number in the i-th line, Ki (0 <= Ki <= N-1), represents the number of rails going out of the i-th intersection. Next Ki numbers represents the intersections directly connected to the i-th intersection.Switch in the i-th intersection is initially pointing in the direction of the first intersection listed.
Output
The first and only line of the output should contain the target minimal number. If there is no route from A to B the line should contain the integer “-1”.
Sample Input
3 2 1 2 2 3 2 3 1 2 1 2
Sample Output
0
Source
Croatia OI 2002 Regional – Juniors
题意:给出N个站点,每个站点都有铁路通向其它的多个站点。
如果当前要走的铁路是现在开关指向的铁路,则直接走即可,否则要手动扳动开关。
难理解的可能是题意:直接指向的 w = 0, 需要手动扳动的 w = 1
第一行给出了站点的总数、起点和终点的标号。
剩下的N行:表示1~N 个站点的铁路连接情况。
每行的第一个数表示该站点的铁路数,第二个数,表示当前默认通往
的站点。
思路:最短路问题 Dijonkstra 算法
把需要扳动的次数看成是路径长度建图即可。
最朴素的Dijkstra 算法分析 PS:来自 《算法竞赛入门经典》 刘汝佳 P202
伪代码:
清除所有点的标号
设d[0]=0, 其它d[i] = INF
循环n次
{
在所有未标号节点中,选出d值 最小的节点 x
标记节点 x
对于从x 出发的说有边(x,y),更新 d[y] = min(d[y], d[x]+w[x][y])
}
对应代码
假设起点节点为0,d[i] 表示起点到i的长度。
v[i]=0 表示未标号 v[i]=1表示已标号
w[x][y]==INF 表示边(x,y) 不存在。
memset(v,0,sizeof(v));
for(int i = 0; i < n; i++) d[i] = (i==0 ? 0 : INF);
for(int i = 0; i < n; i++)
{
int x ,m = INF;
for(int y=0; y<n; y++) if(!v[y] && d[y]<=m) m=d[x=y];
v[x] = 1;
for(int y=0; y<n; y++) d[y] <?= d[x]+w[x][y];
}
//Accepted 212 KB 0 ms C++ 1096 B 2013-02-27 19:42:55
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn = 110;
const int INF = 100000000;
int w[maxn][maxn]; //w[i][j]表示是否连通 0默认 1需手动调节 INF不连通
bool vis[maxn]; //标记是否使用
int dist[maxn]; //dist[i]表示从起点到点i的距离
int n,start,end; //点的个数,起点,终点
void Dijkstra()
{
memset(vis,false,sizeof(vis)); //清除所有的点
for(int i=1;i<=n;i++)
dist[i] = w[start][i];
dist[start] = 0;
vis[start] = true; //标记起点
for(int i=1; i<=n; i++) //循环n 次
{
int x, m = INF;
for(int y = 1; y <= n; y++) //在所有未标号的节点中,选出dist值的最小点x
if(!vis[y] && dist[y] <= m)
m = dist[x=y];
vis[x] = true;//给节点 x 标记
for(int y = 1; y <= n; y++)//更新 松弛操作
dist[y] = min(dist[y],dist[x]+w[x][y]);
}
if(dist[end] == INF) printf("-1\n");
else printf("%d\n", dist[end]);
}
int main()
{
while(scanf("%d%d%d", &n, &start, &end)!=EOF)
{
for(int i=1;i<=n;i++)
{
dist[i] = INF;
for(int j=1;j<=n;j++)
w[i][j] = INF;
}
int path,y;
for(int i=1;i<=n;i++)
{
scanf("%d", &path);
for(int j=1;j<=path;j++)
{
scanf("%d",&y);
if(j==1) w[i][y] = 0;//默认
else w[i][y] = 1; //需手动调节
}
}
Dijkstra();
}
return 0;
}
PS:第一道Dijkstra题目有待优化中。。。。。下面的代码是直接floyd暴力的。。。
//暴力。。。
//Accepted 212 KB 0 ms C++ 1725 B 2013-02-27 19:29:00
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn = 110;
const int INF = 10000000;
int dist[maxn][maxn];
int n,start, end;
int main()
{
scanf("%d%d%d",&n,&start,&end);
{
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
if(i==j) dist[i][j] = 0;
else dist[i][j] = INF;
}
int path,y;
for(int i=1;i<=n;i++)
{
scanf("%d",&path);
for(int j=1;j<=path;j++)
{
scanf("%d",&y);
if(j==1) dist[i][y]=0;
else dist[i][y]=1;
}
}
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
for(int k=1;k<=n;k++)
dist[j][k] =min(dist[j][k],dist[j][i] + dist[i][k] );
}
if(dist[start][end]==INF) printf("-1\n");
else printf("%d\n",dist[start][end]);
return 0;
}