/* *State: POJ1847 16 MS 716 KB GNU C++ *题目大意: * 有N个点以及起点和终点,点与点有路相连。接下来的N行分别为点i的情况: * 第一个数字k表示与该点连通的点的个数,接下来输入k个数,表示与点i相 * 连的点的编号,第一个所连的点为可以不用改扳手而直接通过,其余的点通 * 过的话要改一次扳手,求从起点到终点改扳手的最小次数。 *解题思路: * 原来以为改开关之后,还有后继性,贡献了2个wa,之后分析发现没有环,所以 * 一个点只走一次,开关没有后继性,所以直接建图即可。 */
View Code
#include <queue> #include <iostream> #include <cstdio> #include <cmath> #include <cstring> using namespace std; const int MAXN = 105; const int MAXE = 1000005; const int inf = 0x3f3f3f3f; typedef struct _node { int v, next, is; }N; N edge[2 * MAXE]; int cntEdge, head[MAXN]; typedef struct _no { int v; int dis; _no(): dis(inf) {} _no(int a, int b) : v(a), dis(b) {} friend bool operator < (const struct _no &n1, const struct _no &n2) { return n1.dis > n2.dis; } }priN; void init() { cntEdge = 0; for(int i = 0; i < MAXN; i++) head[i] = -1; } void addEdge(int u, int v, int is) { edge[cntEdge].v = v; edge[cntEdge].is = is; edge[cntEdge].next = head[u]; head[u] = cntEdge++; } int dijkstra(int s, int e, int n)//1是起点,n是终点 { int vst[MAXN] = {0}; int dis[MAXN]; for(int i = 0; i <= n; i++) dis[i] = inf; priority_queue<priN> Q; Q.push(priN(s, 0)); dis[s] = 0; while(!Q.empty()) { priN pre = Q.top(); Q.pop(); if(pre.v == e) return pre.dis; for(int f = head[pre.v]; f != -1; f = edge[f].next) { int son = edge[f].v; int w = edge[f].is; if(dis[son] > dis[pre.v] + w) { dis[son] = dis[pre.v] + w; Q.push(priN(son, dis[son])); } } } return -1; } int main(void) { #ifndef ONLINE_JUDGE //freopen("in.txt", "r", stdin); #endif int n, s, e; while(scanf("%d %d %d", &n, &s, &e) == 3) { init(); int m, v; for(int i = 1; i <= n; i++) { scanf("%d", &m); for(int j = 0; j < m; j++) { scanf("%d", &v); addEdge(i, v, (j == 0 ? 0 : 1)); } } int sol = dijkstra(s, e, n); printf("%d\n", sol); } return 0; }