1. 程式人生 > >圖論 | PAT-A | 1003 Emergency

圖論 | PAT-A | 1003 Emergency

文章目錄

不使用鏈式前向星,使用鄰接矩陣

時間:4 ms

#include <bits/stdc++.h>
#define bug(x) cout<<":x="<<x<<endl;
#define FF(a,b) for(int a=0;a<b;a++)
#define EN 1000
#define VN 500
#define INF (1<<30)-1

using namespace std;
int N,M; int vw[500]; //點權 int dist[VN]; int pre[VN]; int vis[VN]; int pathc[VN]; //最短路條數 int max_vw[VN]; //最大點權 int g[VN][VN]; void dijkstra(int s,int e){ pathc[s]=1; FF(i,N){ dist[i]=INF; pre[i]=-1; } dist[s]=0; max_vw[s]=vw[s]; while(1){ int u=-1,min_d=
INF; FF(i,N) if(!vis[i] && dist[i]<min_d) { min_d=dist[i]; u=i; } if(u<0) break; vis[u]=1; //找到最近點,加入S集 FF(i,N) if(!vis[i] && g[u][i]){ if(dist[i] > dist[u]+g[u][i]) { //s->i > s->u->i
pre[i] = u; dist[i] = dist[u] + g[u][i]; pathc[i] = pathc[u]; max_vw[i]=max_vw[u]+vw[i]; } else if(dist[i]==dist[u]+g[u][i]){ pathc[i] += pathc[u]; if(max_vw[u]+vw[i] > max_vw[i]){ pre[i] = u; dist[i] = dist[u] + g[u][i]; max_vw[i]=max_vw[u]+vw[i]; } } } } printf("%d %d\n",pathc[e],max_vw[e]); FF(i,N){ cout<<dist[i]<<endl; } } int main(){ freopen("../in","r",stdin); int c1,c2; scanf("%d%d%d%d",&N,&M,&c1,&c2); FF(i,N){ int t; scanf("%d",&t); vw[i]=t; } FF(i,M){ int a,b,w; scanf("%d%d%d",&a,&b,&w); g[a][b]=w; g[b][a]=w; } dijkstra(c1,c2); }

使用鏈式前向星, 不堆優化

時間:3 ms

#include <bits/stdc++.h>
#define bug(x) cout<<":x="<<x<<endl;
#define FF(a,b) for(int a=0;a<b;a++)
#define EN 2000
#define VN 500
#define INF (1<<30)-1

using namespace std;

int N,M;
int vw[500];    //點權
int dist[VN];
int pre[VN];
int vis[VN];
int pathc[VN];  //最短路條數
int max_vw[VN];   //最大點權
int g[VN][VN];

int head[EN];    //記錄源點u在mp中第一個地址i=head[u] 呼叫完之後就可以用mp[i]訪問邊表mp
int cnt=0;        //邊表下標,隨著資料的錄入而擴張
struct edge{    //邊
    int to,next,w;
};
edge mp[EN*2];    //邊表
void add(int u,int v,int w){    //增加邊
    mp[cnt].to=v;
    mp[cnt].w=w;
    mp[cnt].next=head[u];    //指向源點u所構成的靜態連結串列的頭結點。如果是首次構造鏈,head[u]=-1 ,相當於NULL
    head[u]=cnt++;            //更新當前地址
}
void init_mp(){
    fill(head,head+EN,-1);
}

void dijkstra(int s,int e){
    pathc[s]=1;
    max_vw[s]=vw[s];
    FF(i,N){
        dist[i]=INF;
        pre[i]=-1;
    }
    dist[s]=0;
    while(1){
        int u=-1,min_d=INF;
        FF(i,N) if(!vis[i] && dist[i]<min_d) {
                min_d=dist[i];
                u=i;
            }
        if(u<0) break;
        vis[u]=1;   //找到最近點,加入S集
        for(int i=head[u];~i;i=mp[i].next){
            int to=mp[i].to;
            if(!vis[to]){
                if(dist[to] > dist[u]+mp[i].w) { //s->to > s->u->to
                    dist[to] = dist[u] + mp[i].w;
                    pre[to]=u;
                    pathc[to] = pathc[u];
                    max_vw[to]=max_vw[u]+vw[to];
                }else if(dist[to]==dist[u]+mp[i].w){
                    pathc[to] += pathc[u];
                    if(max_vw[u]+vw[to] > max_vw[to]){
                        pre[to]=u;
                        dist[to] = dist[u] + mp[i].w;
                        max_vw[to]=max_vw[u]+vw[to];
                    }
                }
            }
        }
    }
    printf("%d %d\n",pathc[e],max_vw[e]);
}

int main(){
    init_mp();
    freopen("../in","r",stdin);
    int c1,c2;
    scanf("%d%d%d%d",&N,&M,&c1,&c2);
    FF(i,N){
        int t;
        scanf("%d",&t);
        vw[i]=t;
    }
    FF(i,M){
        int a,b,w;
        scanf("%d%d%d",&a,&b,&w);
        add(a,b,w);
        add(b,a,w);
        g[a][b]=g[b][a]=w;
    }
    dijkstra(c1,c2);
}

鏈式前向星+堆優化

時間:11 ms

#include <bits/stdc++.h>
#define FF(a,b) for(int a=0;a<b;a++)
#define EN 2000
#define VN 500
#define INF (1<<30)-1

using namespace std;

int N,M;
int vw[500];    //點權
int dist[VN];
int pre[VN];
int vis[VN];
int pathc[VN];  //最短路條數
int max_vw[VN];   //最大點權
int g[VN][VN];

//---------------------鏈式前向星----------------------------
int head[EN];    //記錄源點u在mp中第一個地址i=head[u] 呼叫完之後就可以用mp[i]訪問邊表mp
int cnt=0;        //邊表下標,隨著資料的錄入而擴張
struct edge{    //邊
    int to,next,w;
};
edge mp[EN*2];    //邊表
void add(int u,int v,int w){    //增加邊
    mp[cnt].to=v;
    mp[cnt].w=w;
    mp[cnt].next=head[u];    //指向源點u所構成的靜態連結串列的頭結點。如果是首次構造鏈,head[u]=-1 ,相當於NULL
    head[u]=cnt++;            //更新當前地址
}
void init_mp(){
    fill(head,head+VN,-1);
}
//---------------------鏈式前向星----------------------------

//---------------------堆優化----------------------------
struct cmp{
    bool operator () (int a,int b){
        return dist[a]>dist[b];
    }
};
priority_queue<int,vector<int>,cmp> pq;
//---------------------堆優化----------------------------


void dijkstra(int s,int e){
    fill(dist,dist+N,INF);
    fill(pre,pre+N,-1);
    dist[s]=0;
    pathc[s]=1;
    max_vw[s]=vw[s];
    pq.push(s);     //優先佇列初始化
    while(!pq.empty()){     //優先佇列非空
        int u=pq.top();     //找到最小u點
        pq.pop();
        if(vis[u]) continue;//找到最小u點
        vis[u]=1;   //找到最近點,加入S集
        for(int i=head[u];~i;i=mp[i].next){     //鏈式前向星遍歷
            int to=mp[i].to;    //鏈式前向星: u 的後繼點 to
            int w=mp[i].w;      //鏈式前向星: u -> to 邊權
            if(!vis[to]){   //鬆弛
                if(dist[to] > dist[u]+w) { //s->to > s->u->to
                    dist[to] = dist[u] + w;
                    pre[to]=u;
                    pathc[to] = pathc[u];
                    max_vw[to]=max_vw[u]+vw[to];
                    pq.push(to);    //優先佇列入隊
                }else if(dist[to]==dist[u]+w){
                    pathc[to] += pathc[u];
                    if(max_vw[u]+vw[to] > max_vw[to]){
                        pre[to]=u;
                        dist[to] = dist[u] + w;
                        max_vw[to]=max_vw[u]+vw[to];
                        pq.push(to);    //優先佇列入隊
                    }
                }
            }
        }
    }
    printf("%d %d\n",pathc[e],max_vw[e]);
}

int main(){
    init_mp();  //初始化鏈式前向星
    freopen("../in","r",stdin);
    int c1,c2;
    scanf("%d%d%d%d",&N,&M,&c1,&c2);
    FF(i,N){
        int t;
        scanf("%d",&t);
        vw[i]=t;
    }
    FF(i,M){
        int a,b,w;
        scanf("%d%d%d",&a,&b,&w);
        add(a,b,w);
        add(b,a,w);
        g[a][b]=g[b][a]=w;
    }
    dijkstra(c1,c2);
}