PO2014 Rally

Rally

POI2014

題意

1.有一個N個點M條邊的有向無環圖,每條邊長度都是1

2.找到一個點,使得刪掉這個點後剩餘的圖中的最長路徑最短

3.問刪去的點哪個點,以及刪掉這個點後剩餘的圖中的最長路徑長度爲多少

1.存下每個點的入邊,出邊(分開存)

2.預處理每個點沿着出邊最長鏈是多少(dis2[x]),沿着入邊走最長鏈是多少(dis1[x])

3.先把所有點出邊最長鏈(dis2[x])放進multiset(到時候要查詢最大最小值)

4.按照入度拓撲排序,依次遍歷每個點

5.遍歷到x點時
先把能夠進入它的點(y)與它(x)組成的最長鏈都刪去
y->x 刪去dis1[y]+1+dis2[x]
再刪去x點的出邊最長鏈
刪去dis2[x]

6.此時multiset中的最大值就是刪去x點後的最長鏈長度

7.把能夠從它連出去的點(y)與(x)組成的最長鏈都加入
x->y 加入dis2[y]+1+dis1[x]
把x點的入邊最長鏈加入
加入dis1[x]

具體代碼

#include<bits/stdc++.h>
using namespace std;
const int M=500005;
int n,m,rdu[M],cdu[M],du[M];
int head[M],asdf,rhead[M],rasdf;
multiset<int>S;
multiset<int>::iterator it;
struct edge {
    int to,nxt;
} G[M*2],rG[M*2];
void add_edge(int a,int b) {
    G[++asdf].to=b;
    G[asdf].nxt=head[a];
    head[a]=asdf;
    rG[++rasdf].to=a;
    rG[rasdf].nxt=rhead[b];
    rhead[b]=rasdf;
}
int dis1[M],dis2[M],q[M],l,r;
void init() {
    l=r=1;
    for(int i=1; i<=n; i++) {
        if(!rdu[i])q[r++]=i;
    }
    while(l<r) {
        int x=q[l++];
        for(int i=head[x]; i; i=G[i].nxt) {
            int y=G[i].to;
            if(!(--rdu[y]))q[r++]=y;
            dis1[y]=max(dis1[y],dis1[x]+1);
        }
    }
    l=r=1;
    for(int i=1; i<=n; i++) {
        if(!cdu[i])q[r++]=i;
    }
    while(l<r) {
        int x=q[l++];
        for(int i=rhead[x]; i; i=rG[i].nxt) {
            int y=rG[i].to;
            if(!(--cdu[y]))q[r++]=y;
            dis2[y]=max(dis2[y],dis2[x]+1);
        }
    }
}
void solve() {
    int ans=1e9,px=0;
    l=r=1;
    for(int i=1; i<=n; i++) {
        if(!du[i])q[r++]=i;
        S.insert(dis2[i]);
    }
    while(l<r) {
        int x=q[l++];
        for(int i=rhead[x]; i; i=rG[i].nxt) {
            int y=rG[i].to;
            it=S.find(dis1[y]+1+dis2[x]);
            if(it!=S.end())S.erase(it);
        }
        it=S.find(dis2[x]);
        if(it!=S.end())S.erase(it);
        if(S.size()) {
            it=S.end();
            it--;
            if((*it)<ans) {
                ans=*it;
                px=x;
            }
        }
        S.insert(dis1[x]);
        for(int i=head[x]; i; i=G[i].nxt) {
            int y=G[i].to;
            if(!(--du[y]))q[r++]=y;
            S.insert(dis2[y]+1+dis1[x]);
        }
    }
    printf("%d %d\n",px,ans);
}
int main() {
    int a,b;
    scanf("%d %d",&n,&m);
    for(int i=1; i<=m; i++) {
        scanf("%d %d",&a,&b);
        add_edge(a,b);
        rdu[b]++,cdu[a]++;
        du[b]++;
    }
    init();
    solve();
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章