最短路

题意:
N 个结点、M 个含K 个结点的完全子图构成一个奇怪的图,问从结点1走到结点N 最少需要经过多少个结点。

N100,000 ; K,M1000

分析:
对于每个点,我们可记录包含它的子图序号,然后bfs,加入广搜队列的是子图的序号,显然每个子图只会入队一次。用队列头子图中的所有点来搜索其他子图。

#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;

const int N = 1e3 + 10;
int d[N * 100],G[N * 100],next[N * N],to[N * N];
struct gp {
    int s[N];
} g[N];
int n,m,k,l[2],r[2],tot;
int a[2][N],p[N];

void add(int x,int y) {
    to[++ tot] = y;
    next[tot] = G[x];
    G[x] = tot;
}

int main() {
    scanf("%d%d%d",&n,&k,&m);
    for (int i = 1;i <= m;i ++) {
        for (int j = 1;j <= k;j ++) {
            scanf("%d",&g[i].s[j]);
            add(g[i].s[j],i);
            if (g[i].s[j] == 1) a[0][++ r[0]] = i,p[i] = true;
        }
    }
    memset(d,1,sizeof(d));
    int Inf = d[1],q = 0,dis = 1;
    d[1] = 1;
    while (r[q]) {
        dis ++;
        while (l[q] < r[q]) {
            int x = a[q][++ l[q]];
            for (int i = 1;i <= k;i ++) {
                int cur = g[x].s[i];
                if (d[cur] != Inf) continue;
                d[cur] = dis;
                for (int j = G[g[x].s[i]];j;j = next[j]) {
                    if (p[to[j]]) continue;
                    p[to[j]] = true;
                    a[1 - q][++ r[1 - q]] = to[j];
                }
            }
        }
        l[q] = r[q] = 0;
        q = 1 - q;
        if (d[n] != Inf) break;
    }
    if (d[n] == Inf) printf("-1");else printf("%d",d[n]);
}

你可能感兴趣的:(bfs)