題目描述:
農夫John發現了做出全威斯康辛州最甜的黃油的方法:糖。
把糖放在一片牧場上,他知道 N 只奶牛會過來舔它,這樣就能做出能賣好價錢的超甜黃油。
當然,他將付出額外的費用在奶牛上。
農夫John很狡猾,就像以前的巴甫洛夫,他知道他可以訓練這些奶牛,讓它們在聽到鈴聲時去一個特定的牧場。
他打算將糖放在那裏然後下午發出鈴聲,以至他可以在晚上擠奶。
農夫John知道每隻奶牛都在各自喜歡的牧場(一個牧場不一定只有一頭牛)。
給出各頭牛在的牧場和牧場間的路線,找出使所有牛到達的路程和最短的牧場(他將把糖放在那)。
數據保證至少存在一個牧場和所有牛所在的牧場連通。
輸入格式
第一行: 三個數:奶牛數 N,牧場數 P,牧場間道路數 C。
第二行到第 N+1 行: 1 到 N 頭奶牛所在的牧場號。
第 N+2 行到第 N+C+1 行:每行有三個數:相連的牧場A、B,兩牧場間距 D,當然,連接是雙向的。
輸出格式
共一行,輸出奶牛必須行走的最小的距離和。
數據範圍
1≤N≤500,
2≤P≤800,
1≤C≤1450,
1≤D≤255
輸入樣例:
3 4 5
2
3
4
1 2 1
1 3 5
2 3 7
2 4 3
3 4 5
輸出樣例:
8
分析:
本題要求在圖中找一點,使得該點到給定若干個點的距離之和最小,爲此,我們需要直到任意兩點間的距離,需要求多源最短路。但是Floyd算法時間複雜度是立方級別的,800^3 = 512000000,約是5億多,會超時,所以用解決單源最短路的算法去求解本題,堆優化版的dijkstra算法是O(mlogn),對每個點都執行下dijkstra就是O(mnlogn),1450*2*800*log800約等於2000多w,可以通過。因此本題的解法就是對每個點求下最短路,然後計算下到奶牛所在地的距離和,最後取最小值即可。
唯一要注意的是並不是所有的頂點都可以到達,因此,當從某個頂點出發到達不了奶牛所在地時,距離和可能會爆int,導致最後輸出的是負數,所以求距離和的時候要判斷下是否存在不可達的點。
#include <iostream>
#include <cstring>
#include <algorithm>
#include <queue>
using namespace std;
const int N = 805,M = 2905,INF = 0x3f3f3f3f;
typedef pair<int,int> PII;
int n,m,k,d[N],c[N];
int idx,h[N],e[M],ne[M],w[M];
bool st[N];
priority_queue<PII> pq;
void add(int a,int b,int c){
e[idx]=b,w[idx]=c,ne[idx]=h[a],h[a]=idx++;
}
int dijkstra(int s){
memset(st,false,sizeof st);
memset(d,0x3f,sizeof d);
d[s] = 0;
pq.push({-d[s],s});
while(pq.size()){
int u = pq.top().second;
pq.pop();
if(st[u]) continue;
st[u] = true;
for(int i = h[u];~i;i = ne[i]){
int j = e[i];
if(!st[j] && d[j] > d[u] + w[i]){
d[j] = d[u] + w[i];
pq.push({-d[j],j});
}
}
}
int ans = 0;
for(int i = 0;i < k;i++){
ans += d[c[i]];
if(ans > INF) return INF;
}
return ans;
}
int main(){
scanf("%d%d%d",&k,&n,&m);
memset(h,-1,sizeof h);
for(int i = 0;i < k;i++) scanf("%d",&c[i]);
int x,y,z;
for(int i = 0;i < m;i++){
scanf("%d%d%d",&x,&y,&z);
add(x,y,z),add(y,x,z);
}
int ans = INF;
for(int i = 1;i <= n;i++) ans = min(ans,dijkstra(i));
printf("%d\n",ans);
return 0;
}
spfa算法的時間複雜度是O(m),執行n次就是O(mn),只要兩百多萬執行次數,效率更加高效。
#include <iostream>
#include <cstring>
#include <algorithm>
#include <queue>
using namespace std;
const int N = 805,M = 2905,INF = 0x3f3f3f3f;
int n,m,k,d[N],c[N];
int idx,h[N],e[M],ne[M],w[M];
bool st[N];
queue<int> q;
void add(int a,int b,int c){
e[idx]=b,w[idx]=c,ne[idx]=h[a],h[a]=idx++;
}
int dijkstra(int s){
memset(st,false,sizeof st);
memset(d,0x3f,sizeof d);
d[s] = 0;
q.push(s);
st[s] = true;
while(q.size()){
int u = q.front();
q.pop();
st[u] = false;
for(int i = h[u];~i;i = ne[i]){
int j = e[i];
if(d[j] > d[u] + w[i]){
d[j] = d[u] + w[i];
if(!st[j]){
q.push(j);
st[j] = true;
}
}
}
}
int ans = 0;
for(int i = 0;i < k;i++){
ans += d[c[i]];
if(ans > INF) return INF;
}
return ans;
}
int main(){
scanf("%d%d%d",&k,&n,&m);
memset(h,-1,sizeof h);
for(int i = 0;i < k;i++) scanf("%d",&c[i]);
int x,y,z;
for(int i = 0;i < m;i++){
scanf("%d%d%d",&x,&y,&z);
add(x,y,z),add(y,x,z);
}
int ans = INF;
for(int i = 1;i <= n;i++) ans = min(ans,dijkstra(i));
printf("%d\n",ans);
return 0;
}