题目链接:http://poj.org/problem?id=1847

        题意是输入n,a,b三个数,表示有n个点(1-n),起点是a,终点是b,然后接下来有n行,每一行的第一个数m表示后面将会有m个数,输入结构是这样的,然后我再具体的解释一下。

    3 2 1     3表示共有n个点,接下来有n行,2表示起点,1表示终点
    2 2 3     第一个数2表示后面有2个数,因为这是第1行,所以后面两个数表示从1到2和从1到3的边
    2 3 1     表示从2到3和从2到1的边
    2 1 2     表示从3到1和从3到2的边

       因为每个点都有开关,第一个点是不需要开开关的,但是之后的每一个都要开开关,意思是输入m后的第一条边是不需要开开关的,后面的2-m的边都是需要开开关的,比如样例的第二行,2 2 3就是1-2这条边不需要开开关,1-3这条边需要开开关。这道题最后问的就是从a点到b点,最少需要开多少个开关,题意很难读懂,懂了以后这道题就很简单了,把用不用开开关的作为边的权值,不用开开关的权值为0,用开开关的边权值为1,然后跑个dij就好了。


AC代码:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>
#define inf 0x3f3f3f3f
#define maxn 505
using namespace std;
struct Node{
  int to,w,next;
  bool operator < (const Node &a) const {
    return a.w < w;
  }
}Edge[maxn * maxn],Now,Next;
int head[maxn * maxn],num;
int n,m,a,b;

void init(){
  memset(head,-1,sizeof(head));
  num = 0;
}

void add(int u,int v,int w){
  Edge[num].to = v;
  Edge[num].w = w;
  Edge[num].next = head[u];
  head[u] = num ++;
}

void dijkstra(){
  int dist[maxn];
  bool vis[maxn];
  memset(dist,inf,sizeof(dist));
  memset(vis,false,sizeof(vis));
  dist[a] = 0;
  Now.to = a;
  priority_queue<Node> q;
  q.push(Now);
  while(!q.empty()){
    Now = q.top();
    q.pop();
    int ans = Now.to;
    if(vis[ans]) continue;
    vis[ans] = true;
    for(int i=head[ans];i!=-1;i=Edge[i].next){
      int u = Edge[i].to;
      if(!vis[u] && dist[u] > dist[ans] + Edge[i].w){
        dist[u] = dist[ans] + Edge[i].w;
        Next.to = u;
        Next.w = dist[u];
        q.push(Next);
      }
    }
  }
  printf("%d\n",dist[b] == inf ? -1 : dist[b]);
}

int main()
{
  scanf("%d%d%d",&n,&a,&b);
  init();
  for(int i=1;i<=n;i++){
    scanf("%d",&m);
    int v;
    scanf("%d",&v);
    add(i, v, 0);
    for(int j=1;j<m;j++){
      scanf("%d",&v);
      add(i, v, 1);
    }
  }
  dijkstra();
  return 0;
}