zoukankan      html  css  js  c++  java
  • POJ 1847

    萨格勒布的电车网络包括许多交叉路口和连接其中一些的铁路。在每个交叉路口,都有一个开关指向离开交叉路口的一条导轨。有轨电车进入交叉路口时,只能沿开关指向的方向离开。如果驾驶员想走其他路线,则必须手动更改开关。

    当驾驶员确实从交叉路口A到交叉路口B行驶时,他/她试图选择一条路线,该路线将最大限度地减少他/她将不得不手动更改开关的次数。

    编写一个程序,计算从路口A到路口B所需的最少开关变化次数。

    Input

    输入的第一行包含整数N,A和B,以单个空白字符分隔,2 <= N <= 100,1 <= A,B <= N,N是网络中的交点数,并且交叉点从1到N编号。

    接下来的N行中的每行均包含由单个空白字符分隔的整数序列。第i行中的第一个数字Ki(0 <= Ki <= N-1)表示从第i个交叉点出来的轨道数。下一个Ki数字表示直接连接到第i个交叉点的交叉点。第i个交叉点的开关最初指向列出的第一个交叉点的方向。

    Output

    输出的第一行和唯一行应包含目标最小值。如果没有从A到B的路线,则该行应包含整数“ -1”。

    Sample Input

    3 2 1
    2 2 3
    2 3 1
    2 1 2

    Sample Output

    0

    题目大意:

    在一个城市里有一个电车道路网,然后有一些岔路口,第一行输入三个数N A B 表示有N个岔路口,需要从A走到B,然后输入n行,对于第 i 行,先输入一个k表示有k个分叉,之后输入k个节点,j1…jk 表示从i -> j 是可行的,但是每个岔路口都有开关,默认的开关打到了每个岔路口的第一个路口,即3 1 2 3 表示有3个路口,可以通向1 2 3 ,但是开关默认指向1。 这句话很重要,影响到后面的建图,对于开关指向的区域可以直接走,对于没有指向的岔路口则需要手动操作,更改开关指向想要去的路口,最后要求输出A 到 B最小的操作数。

    解题思路:

    比较简单的一道最短路,重要的是读题,建图需要一些技巧,这里的权值就是操作数了。因为起初的开关指向第一个,所以从第二行开始,每行的第一个数权值应该是0,之后都是1才对,建有向边,之后跑spfa即可AC。

    Code:

    #include <cstdio>
    #include <iostream>
    #include <algorithm>
    #include <cstring>
    #include <iomanip>
    #include <sstream>
    #include <cmath>
    #include <vector>
    #include <queue>
    #include <stack>
    #include <map>
    #include <set>
    #define lowbit(x) x & (-x)
    
    using namespace std;
    
    typedef long long ll;
    typedef pair<int, int> pii;
    
    const int mod = 1e9 + 7;
    const int inf = 0x3f3f3f3f;
    const int N = 1e4 + 50;
    const int M = 200 + 50;
    
    int h[N], ne[N], e[N], w[N], idx;
    int dis[N];
    bool vis[N];
    int n, a, b;
    
    void add(int a, int b, int c)
    {
    	e[idx] = b;
    	w[idx] = c;
    	ne[idx] = h[a];
    	h[a] = idx++;
    }
    
    void spfa(int s)
    {
    	memset(dis, 0x3f, sizeof dis);
    	dis[s] = 0;
    
    	queue<int > q;
    	q.push(s);
    	vis[s] = true;
    
    	while (!q.empty())
    	{
    		int t = q.front();
    		q.pop();
    		vis[t] = false;
    
    		for (int i = h[t]; ~i; i = ne[i])
    		{
    
    			int j = e[i];
    			if (dis[t] + w[i] < dis[j])
    			{
    				dis[j] = dis[t] + w[i];
    				if (!vis[j])
    				{
    					q.push(j);
    					vis[j] = true;
    				}
    			}
    		}
    	}
    }
    
    int main()
    {
    	scanf("%d%d%d", &n, &a, &b);
    	memset(h, -1, sizeof h);
    	for (int i = 1; i <= n; i ++)
    	{
    		int k;
    		scanf("%d", &k);
    		for (int j = 1; j <= k; j ++)
    		{
    			int t;
    			scanf("%d", &t);
    			if (j == 1) add(i, t, 0);//第一个权值要建成00
    			else add(i, t, 1);
    		}
    	}
    
    	spfa(a);
    
    	printf("%d", dis[b] == inf ? -1 : dis[b]);
    
    	return 0;
    }
    
  • 相关阅读:
    ubuntu+VS code+launch.json+task.json
    C++——运行时类型识别RTTI
    C++——模板
    C++——class类和struct结构体的唯一区别
    C++——右值引用
    C++——智能指针
    身份证号码格式检测
    PHP获取图片主题颜色
    PHP 压缩图片质量
    redis3.2装完后 其它机子访问爆protocol error, got 'n' as reply type byte
  • 原文地址:https://www.cnblogs.com/Hayasaka/p/14294121.html
Copyright © 2011-2022 走看看