圖論 | PAT-A | 1003 Emergency
阿新 • • 發佈:2019-01-02
文章目錄
不使用鏈式前向星,使用鄰接矩陣
時間: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);
}