poj3114 Countries in War 强连通分量+dijkstra或者DAG最短路

20 篇文章 0 订阅
10 篇文章 0 订阅

思路:先求出各个强联通分量,缩点,由于国家内部通信的不需要时间的,一个国内的某个城市和另一个国家内的某个城市通信等价与两个国家之间通信。


之后就是一套最短路的东西了,由于缩点之后是DAG,所以可以用DAG的最短路来求,但事实证明这个没有堆优化的dijkstra快。


#include<stdio.h>
#include<queue>
#include<string.h>

using namespace std;

const int N = 512;
const int INF = 0x3f3f3f3f;

int cnt, fir[N], fir1[N];
int dfn[N];
int low[N], stack1[N], stack2[N];
int dis[N][N];
int indeg[N];
int scc[N];
int myque[N];
int n, tstamp, sccNum, top1, top2, cnt1, qfront;

struct Edge {
    int v, w, next;
};

struct Node {
    int v, w;
    Node() {};
    Node(int pv, int pw):v(pv), w(pw) {};
    bool operator < (const Node& other) const {
        return w > other.w;
    }
};

Edge edge[N*N];
Edge edge1[N*N];

void init() {
    cnt = cnt1 = 0;
    memset(fir, -1, sizeof(fir));
    memset(fir1, -1, sizeof(fir1));

    memset(indeg, 0, sizeof(indeg));
}

void addEdge(int u, int v, int w) {
    edge[cnt].v = v;
    edge[cnt].w = w;
    edge[cnt].next = fir[u];
    fir[u] = cnt++;
}

void addEdge1(int u, int v, int w) {
    edge1[cnt1].v = v;
    edge1[cnt1].w = w;
    edge1[cnt1].next = fir1[u];
    fir1[u] = cnt1++;
}

void gardfs(int cur) {
    low[cur] = ++tstamp;
    stack1[++top1] = cur;
    stack2[++top2] = cur;
    for(int i = fir[cur]; i != -1; i = edge[i].next) {
        int v = edge[i].v;
        if(!low[v]) {
            gardfs(v);
        } else if(!scc[v]) {
            while(low[stack2[top2]] > low[v])
                top2--;
        }
    }
    if(stack2[top2] == cur) {
        top2--;
        sccNum++;
        do {
            scc[stack1[top1]] = sccNum;
        } while(stack1[top1--] != cur);
    }
}

void garbow() {
    memset(low, 0, sizeof(low));
    memset(scc, 0, sizeof(scc));
    top1 = top2 = tstamp = sccNum = 0;
    for(int i = 1; i <= n; i++)
        if(!low[i]) gardfs(i);
}

void dijkstra(int s) {
    priority_queue<Node> pque;
    dis[s][s] = 0;
    pque.push(Node(s, dis[s][s]));
    while(!pque.empty()) {
        Node cur = pque.top();
        pque.pop();
        for(int i = fir1[cur.v]; i != -1; i = edge1[i].next) {
            int v = edge1[i].v;
            if(dis[s][v] > dis[s][cur.v] + edge1[i].w) {
                dis[s][v] = dis[s][cur.v] + edge1[i].w;
                pque.push(Node(v, dis[s][v]));
            }
        }
    }
}

void toposort() {
    qfront = 1;
    for(int i = 1; i <= sccNum; i++) {
        if(indeg[i] == 0)
            myque[qfront++] = i;
    }
    for(int i = 1; i <= sccNum; i++) {
        for(int j = fir1[myque[i]]; j != -1; j = edge1[j].next) {
            int v = edge1[j].v;
            indeg[v]--;
            if(indeg[v] == 0)
                myque[qfront++] = v;
        }
    }
}

void DAGPath(int s) {
    dis[s][s] = 0;
    for(int i = 1; i < qfront; i++) {
        for(int j = fir1[myque[i]]; j != -1; j = edge1[j].next) {
            int v = edge1[j].v;
            if(dis[s][v] > dis[s][myque[i]] + edge1[j].w) {
                dis[s][v] = dis[s][myque[i]] + edge1[j].w;
            }
        }
    }
}

int main() {
    int m;
    while(~scanf("%d%d", &n, &m), n) {
        init();
        for(int i = 0; i < m; i++) {
            int u, v, w;
            scanf("%d%d%d", &u, &v, &w);
            addEdge(u, v, w);
        }
        garbow();
        memset(dis, INF, sizeof(dis));
        for(int i = 1; i <= n; i++) {
            for(int j = fir[i]; j != -1; j = edge[j].next) {
                int v = edge[j].v;
                if(scc[i] != scc[v]) {
                    addEdge1(scc[i], scc[v], edge[j].w);
                    indeg[scc[v]] ++;
                }
            }
        }
        toposort();
        for(int i = 1; i <= sccNum; i++) {
                DAGPath(i);
                //dijkstra(i);
        }
        int k;
        scanf("%d", &k);
        while(k--) {
            int u, v;
            scanf("%d%d", &u, &v);
            if(scc[u] == scc[v]) {
                printf("0\n");
                continue;
            }
            if(dis[scc[u]][scc[v]] != INF) {
                printf("%d\n", dis[scc[u]][scc[v]]);
            } else printf("Nao e possivel entregar a carta\n");
        }
        printf("\n");
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值