2019安徽省程序設計競賽 D.自駕游(最短路)


這道題最后沒過,估計是痛失省一了,現在來補一下,當時思路是對的應該是代碼出了問題導致樣例沒過最后nc的除了2,一直WA

題意:

給一張聯通圖,有兩個導航系統,其中一個系統認為第i條邊的權值是Pi,另一個系統認為是Qi(給定Pi和Qi),然后每個導航系統對於每條邊i有個判定

其中一個是hero(vi)+Pi>hero(ui)會報警一次,另一個系統是a(vi)+Qi>a(ui)會報警一次,ui是邊i的一個結點vi是另一個結點,讓求一條兩個系統警告次數相加最少的一條路徑。

思路:

先從終點n作為起點跑兩次最短路,一個按Pi為權值,求出每個節點v的hero(v),第二次以Qi為權值,求出每個節點v的a(v)。

然后遍歷每條邊,用警告次數作為權值從1作為起點再跑一次最短路求出結果即可。最短路的求法我用了Dij+堆優化。

這個改正過的代碼只過了樣例,沒法實際測試了,有不對的地方還請大佬指正。

樣例數據:

Sample input

5 7
3 4 7 1
1 3 2 20
1 4 17 18
4 5 25 3
1 2 10 1
3 5 4 14
2 4 6 5

Sample output

1

#include <bits/stdc++.h>
using namespace std;

const int maxn = 1e4 + 5;
const int maxm = 5e4 + 5;
const int inf = 0x3f3f3f3f;
struct edge{
    int to, wp, wq, ww, next;
} ed[maxm*2];
int n, m, head[maxn], tot;
int hero[maxn], a[maxn], dis[maxn];
bool vis[maxn];
inline void add( int u, int v, int p, int q ){
    ed[tot].to = v;
    ed[tot].wp = p;
    ed[tot].wq = q;
    ed[tot].ww = 0;
    ed[tot].next = head[u];
    head[u] = tot ++;
}

inline void dij1(int s){
    memset( vis, 0, sizeof(vis) );
    memset( hero, inf, sizeof(hero) );
    priority_queue< pair<int, int> > q;
    vis[s] = 1;
    hero[s] = 0;
    q.push( make_pair( 0, s ) );
    while( !q.empty() ){
        int u = q.top().second;
        q.pop();
        for( int i=head[u]; i!=-1; i=ed[i].next ){
            int v = ed[i].to;
            if( hero[v]>hero[u]+ed[i].wp ){
                hero[v] = hero[u]+ed[i].wp;
                if( !vis[v] ){
                    vis[v] = 1;
                    q.push( make_pair( -hero[v], v ) );
                }
            }
        }
    }
}

inline void dij2(int s){
    memset( vis, 0, sizeof(vis) );
    memset( a, inf, sizeof(a) );
    priority_queue< pair<int, int> > q;
    a[s] = 0;
    q.push( make_pair( 0, s ) );
    while( !q.empty() ){
        int u = q.top().second;
        q.pop();
        if( vis[u] ) continue;
        vis[u] = 1;
        for( int i=head[u]; i!=-1; i=ed[i].next ){
            int v = ed[i].to;
            if( a[v]>a[u]+ed[i].wq ){
                a[v] = a[u]+ed[i].wq;
                q.push( make_pair(-a[v], v) );
            }
        }
    }
}

inline void dij3( int s ){
    memset( vis, 0, sizeof(vis) );
    memset( dis, inf, sizeof(dis) );
    priority_queue< pair<int, int> > q;
    dis[s] = 0;
    q.push( make_pair( 0, s ) );
    while( !q.empty() ){
        int u = q.top().second;
        q.pop();
        if( vis[u] ) continue;
        vis[u] = 1;
        for( int i=head[u]; i!=-1; i=ed[i].next ){
            int v = ed[i].to;
            if( dis[v]>dis[u]+ed[i].ww ){
                dis[v] = dis[u]+ed[i].ww;
                q.push( make_pair( -dis[v], v ) );
            }
        }
    }
}

inline void bfs(int s){
    queue<int> q;
    memset( vis, 0, sizeof(vis) );
    vis[s] = 1;
    q.push(s);
    while( !q.empty() ){
        int u = q.front();
        q.pop();
        for( int i=head[u]; i!=-1; i=ed[i].next ){
            int v = ed[i].to;
            if( !vis[v] ){
                vis[v] = 1;
                if( hero[v]+ed[i].wp>hero[u] ) ed[i].ww ++;
                if( a[v]+ed[i].wq>a[u] ) ed[i].ww ++;
            }
        }
    }
}

int main(){
    // freopen("in.txt", "r", stdin);
    tot = 0;
    memset( head, -1, sizeof(head) );
    scanf("%d%d", &n, &m);
    for( int i=0; i<m; i++ ){
        int u, v, p, q;
        scanf("%d%d%d%d", &u, &v, &p, &q);
        add( u, v, p, q );
        add( v, u, p, q );
    }
    dij1(n);
    dij2(n);
    //注釋掉的就是當時寫的錯誤遍歷邊的代碼
    // for( int i=1; i<=n; i++ ){
    //     for( int j=head[i]; j!=-1; j=ed[j].next ){
    //         if( ed[j].wp+hero[ed[j].to]>hero[i] ) ed[j].ww ++;
    //         if( ed[j].wq+a[ed[j].to]>a[i] ) ed[j].ww ++;
    //     }
    // }
    bfs(1);        //應該從1開始向外bfs遍歷邊,即可找出正確答案
    dij3(1);
    printf("%d\n", dis[n]);

    return 0;
}

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM