AcWing 1127 香甜的黃油

題目描述:

農夫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;
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章