BZOJ_2200

    这个题目一看就知道SPFA可做,但是SPFA就是超时……

    USACO上给出的解法的大致意思是:由于每条航线都是单向的,而且不存在从航线的终点辗转到航线起点的通路,那么就是说航线将原图分成了若干个相对封闭的区域,我们把航线从原图中拿掉后,剩下的就应当是若干个连通块。由于每个连通块中只有非负权边,那么我们就可以在连通块内用Dijkstra求最短路了。而且从S开始做最短路时,这些连通块是有一定的拓扑关系的,也就是说只有先确定了S到某些连通块中的点的最短路,才能确定S到另一些连通块中的点的最短路,这样按连通块的拓扑顺序,一个连通块一个连通块的不断地求最短路,就可以得到S到每个点的最短路了。

#include<stdio.h>
#include<string.h>
#include<vector>
#include<queue>
#define MAXD 25010
#define INF 0x3f3f3f3f
struct Edge
{
    int v, c;
    Edge(){}
    Edge(int _v, int _c) : v(_v), c(_c){}
};
std::vector<Edge> road[MAXD], fly[MAXD];
int T, R, P, S;
void init()
{
    int x, y, c;
    for(int i = 1; i <= T; i ++) road[i].clear(), fly[i].clear();
    for(int i = 0; i < R; i ++)
    {
        scanf("%d%d%d", &x, &y, &c);
        road[x].push_back(Edge(y, c)), road[y].push_back(Edge(x, c));

    }
    for(int i = 0; i < P; i ++)
    {
        scanf("%d%d%d", &x, &y, &c);
        fly[x].push_back(Edge(y, c));
    }
}
int p[MAXD], dgr[MAXD], dis[MAXD], cal[MAXD];
struct St
{
    int id, v;
    St(){}
    St(int _id, int _v) : id(_id), v(_v){}
    bool operator < (const St &t) const
    {
        return v > t.v;
    }
};
int find(int x)
{
    return p[x] == x ? x : (p[x] = find(p[x]));
}
void bfs()
{
    memset(dgr, 0, sizeof(dgr[0]) * (T + 1));
    std::queue<int> q;
    memset(cal, 0, sizeof(cal[0]) * (T + 1));
    cal[S] = 1, q.push(S);
    while(!q.empty())
    {
        int x = q.front();
        q.pop();
        for(int i = 0; i < road[x].size(); i ++)
        {
            int y = road[x][i].v;
            if(!cal[y]) cal[y] = 1, q.push(y);
        }
        for(int i = 0; i < fly[x].size(); i ++)
        {
            int y = fly[x][i].v;
            ++ dgr[find(y)];
            if(!cal[y]) cal[y] = 1, q.push(y);
        }
    }
}
void dij(int set, std::queue<int> &wait, std::vector<int> ini[])
{
    std::priority_queue<St> q;
    for(int i = 0; i < ini[set].size(); i ++)
    {
        int x = ini[set][i];
        q.push(St(x, dis[x]));
    }
    while(!q.empty())
    {
        St st = q.top();
        q.pop();
        int x = st.id;
        if(cal[x]) continue;
        cal[x] = 1;
        for(int i = 0; i < road[x].size(); i ++)
        {
            int y = road[x][i].v, c = road[x][i].c;
            if(dis[x] + c < dis[y]) dis[y] = dis[x] + c, q.push(St(y, dis[y]));
        }
        for(int i = 0; i < fly[x].size(); i ++)
        {
            int y = fly[x][i].v, c = fly[x][i].c, set = find(y);
            -- dgr[set];
            if(dgr[set] == 0) wait.push(set);
            if(dis[x] + c < dis[y]) dis[y] = dis[x] + c, ini[set].push_back(y);
        }
    }
}
void solve()
{
    for(int i = 1; i <= T; i ++) p[i] = i;
    for(int i = 1; i <= T; i ++)
        for(int j = 0; j < road[i].size(); j ++)
        {
            int x = find(i), y = find(road[i][j].v);
            if(x != y) p[x] = y;
        }
    bfs();
    std::vector<int> ini[MAXD];
    std::queue<int> wait;
    memset(dis, 0x3f, sizeof(dis[0]) * (T + 1));
    dis[S] = 0, ini[find(S)].push_back(S), wait.push(find(S));
    memset(cal, 0, sizeof(cal[0]) * (T + 1));
    while(!wait.empty())
    {
        int set = wait.front();
        wait.pop();
        dij(set, wait, ini);
    }
    for(int i = 1; i <= T; i ++)
    {
        if(dis[i] == INF) printf("NO PATH\n");
        else printf("%d\n", dis[i]);
    }
}
int main()
{
    while(scanf("%d%d%d%d", &T, &R, &P, &S) == 4)
    {
        init();
        solve();
    }
    return 0;
}

 

 

posted on 2012-10-01 03:21  Staginner  阅读(929)  评论(0编辑  收藏  举报