信息学奥赛一本通 1345:【例4-6】香甜的黄油 | 洛谷 P1828 [USACO3.2]香甜的黄油 Sweet Butter
生活随笔
收集整理的這篇文章主要介紹了
信息学奥赛一本通 1345:【例4-6】香甜的黄油 | 洛谷 P1828 [USACO3.2]香甜的黄油 Sweet Butter
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
【題目鏈接】
ybt 1345:【例4-6】香甜的黃油
洛谷 P1828 [USACO3.2]香甜的黃油 Sweet Butter
【題目考點】
1. 圖論 最短路徑
【解題思路】
將題目敘述轉為圖論概念,牧場為頂點,牧場間的路線為邊。該題一個頂點上有多頭牛,這個后面再考慮。
記有V個頂點,E條邊,有n頭牛,每頭牛所在頂點為v1,v2,...vnv_1,v_2,...v_nv1?,v2?,...vn?,d(i,j)d(i,j)d(i,j)為頂點i,j間的最短路徑長度。
題目要問的問題是,選擇一個頂點c,使得∑i=1nd(vi,c)\sum_{i=1}^nd(v_i,c)∑i=1n?d(vi?,c)最小。
如果已知每頭牛所在頂點到其它任意頂點的最短路徑長度,那么接下來就可以遍歷所有頂點,記遍歷到的頂點為i,選擇頂點i為放糖的地方,求所有牛所在頂點到頂點i的最短路徑加和,這一步的復雜度為O(V?n)O(V\cdot n)O(V?n)
問題落在如何求每頭牛所在頂點到其它任意頂點的最短路徑。
- 使用Floyd算法,求所有頂點間的最短路徑長度。題目給定頂點數(牧場數)最大為800,Floyd算法的復雜度為O(V3)O(V^3)O(V3),8003=5.12?108800^3=5.12*10^88003=5.12?108,運算次數在10710^7107以下可以保證不會超時,復雜度達到10810^8108數量級很可能會超時,所以不能用Floyd算法。
如果用單源最短路徑算法,需要對每頭牛所在頂點跑一次單源最短路徑算法。算法整體復雜度為:O(n)O(n)O(n)乘以所用的單源最短路徑算法的復雜度。 - 考慮使用樸素Dijkstra算法,整體復雜度為O(n?V2)O(n\cdot V^2)O(n?V2),計算500?8002=3.2?108500*800^2=3.2*10^8500?8002=3.2?108,不可行。
- 使用Dijkstra堆優化算法,整體復雜度為O(n?ElogE)O(n\cdot ElogE)O(n?ElogE),題目中邊數最多約為1500,計算500?1500?log21500≈8.25?106500*1500*log_21500\approx8.25*10^6500?1500?log2?1500≈8.25?106,可行。
- 使用SPFA算法,復雜度為O(kE)O(kE)O(kE),k為每個頂點平均入隊次數,在稀疏圖中一般小于2,可以認為等于2。用SPFA算法做該問題,整體復雜度為O(n?kE)O(n\cdot kE)O(n?kE),計算500?2?1500=1.5?106500*2*1500 = 1.5*10^6500?2?1500=1.5?106,可行。
以上是思考過程,該題做法為:
【題解代碼】
解法1:Dijkstra堆優化算法
#include<bits/stdc++.h> using namespace std; #define N 805 #define INF 0x3f3f3f3f struct Pair {int v, d;Pair(){}Pair(int a, int b):v(a),d(b){}bool operator < (const Pair &b) const{return b.d < d;} }; struct Edge {int t, w;Edge(){}Edge(int a, int b):t(a),w(b){} }; int n, p, c; bool vis[N]; int dis[N][N];//dis[i][j]:i到j的最短路徑長度 int place[N];//place[i]:牛i所在的頂點 vector<Edge> edge[N]; void initGraph() {int f, t, w;cin >> n >> p >> c;for(int i = 1; i <= n; ++i)cin >> place[i];for(int i = 1; i <= c; ++i){cin >> f >> t >> w;edge[f].push_back(Edge(t, w));edge[t].push_back(Edge(f, w));} } void dijkstra(int v0) {memset(vis, 0, sizeof(vis));priority_queue<Pair> pq;dis[v0][v0] = 0;pq.push(Pair(v0, 0));while(pq.empty() == false){int u = pq.top().v;pq.pop();if(vis[u])continue;vis[u] = true;for(int i = 0; i < edge[u].size(); ++i){int v = edge[u][i].t, w = edge[u][i].w;if(vis[v] == false && dis[v0][v] > dis[v0][u] + w){dis[v0][v] = dis[v0][u] + w;pq.push(Pair(v, dis[v0][v]));}}} } int main() {int v0, sum, ans = INF;initGraph();memset(dis, 0x3f, sizeof(dis));for(int i = 1; i <= n; ++i){v0 = place[i];//起點 if(dis[v0][v0] == INF)//如果該頂點的單源最短路徑問題沒有求過了 dijkstra(v0);}for(int i = 1; i <= p; ++i){//在頂點i放糖 sum = 0;for(int j = 1; j <= n; ++j)sum += dis[place[j]][i];ans = min(ans, sum);}cout << ans;return 0; }解法2:SPFA算法
#include<bits/stdc++.h> using namespace std; #define N 805 #define INF 0x3f3f3f3f struct Pair {int v, d;Pair(){}Pair(int a, int b):v(a),d(b){}bool operator < (const Pair &b) const{return b.d < d;} }; struct Edge {int t, w;Edge(){}Edge(int a, int b):t(a),w(b){} }; int n, p, c; bool vis[N]; int dis[N][N];//dis[i][j]:i到j的最短路徑長度 int place[N];//place[i]:牛i所在的頂點 vector<Edge> edge[N]; void initGraph() {int f, t, w;cin >> n >> p >> c;for(int i = 1; i <= n; ++i)cin >> place[i];for(int i = 1; i <= c; ++i){cin >> f >> t >> w;edge[f].push_back(Edge(t, w));edge[t].push_back(Edge(f, w));} } void spfa(int v0) {memset(vis, 0, sizeof(vis));queue<int> que;dis[v0][v0] = 0;que.push(v0);vis[v0] = true;while(que.empty() == false){int u = que.front();que.pop();vis[u] = false;for(int i = 0; i < edge[u].size(); ++i){int v = edge[u][i].t, w = edge[u][i].w;if(dis[v0][v] > dis[v0][u] + w){dis[v0][v] = dis[v0][u] + w;if(vis[v] == false){que.push(v);vis[v] = true;}}}} } int main() {int v0, sum, ans = INF;initGraph();memset(dis, 0x3f, sizeof(dis));for(int i = 1; i <= n; ++i){v0 = place[i];//起點 if(dis[v0][v0] == INF)//如果該頂點的單源最短路徑問題沒有求過了 spfa(v0);}for(int i = 1; i <= p; ++i){//在頂點i放糖 sum = 0;for(int j = 1; j <= n; ++j)sum += dis[place[j]][i];ans = min(ans, sum);}cout << ans;return 0; }總結
以上是生活随笔為你收集整理的信息学奥赛一本通 1345:【例4-6】香甜的黄油 | 洛谷 P1828 [USACO3.2]香甜的黄油 Sweet Butter的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 信息学奥赛一本通 1226:装箱问题 |
- 下一篇: java println源码_Syste