b_lg_郵局(暴力dp / 預處理優化 / 四邊形不等式)
阿新 • • 發佈:2020-09-15
為了建立郵局,應選擇他們建造的位置,使每個村莊與其最近的郵局之間的距離總和最小。
你要編寫一個程式,已知村莊的位置和郵局的數量,計算每個村莊和最近的郵局之間所有距離的最小可能的總和。
輸出格式
第一行包含一個整數S,它是每個村莊與其最近的郵局之間的所有距離的總和。
方法一:dp
蒙的:一個郵局放在中間位置得到的距離總和最小;
- 定義狀態:
- f[i][j] 表示在前i個村莊中建j個郵局的最小距離總和
- 思考初始化:
- f[...][...]=+inf, f[0][0]=0
- 思考狀態轉移方程:
- f[i][j]=min(f[i][j], f[k][j-1]+dist(k+1, i)),看是更優:前i個村莊中建j個郵局的最小距離 | 在前k個村莊中建j-1個以及第j個郵局在k+1到i這些村莊中建立的距離
- 思考輸出:f[V][P]
\(O(v^3 × p)\)tle之40/100...
#include<bits/stdc++.h> using namespace std; typedef long long ll; const int V=3005, P=305, inf=0x3f3f3f3f; int v,p,f[V][P],A[V]; int dist(int l, int r) { int m=l+(r-l)/2, ans=0; for (int i=l; i<m; i++) ans+=A[m]-A[i]; for (int i=m+1; i<=r; i++) ans+=A[i]-A[m]; return ans; } int main() { std::ios::sync_with_stdio(false); cin.tie(0); cout.tie(0); cin>>v>>p; for (int i=1; i<=v; i++) cin>>A[i]; memset(f, inf, sizeof f); f[0][0]=0; for (int j=1; j<=p; j++) //郵局 for (int i=1; i<=v; i++) //村莊 for (int k=0; k<i; k++) { //少量村莊 f[i][j]=min(f[i][j], f[k][j-1]+dist(k+1, i)); } cout << f[v][p]; return 0; }
預處理每個村莊中心到其它點的距離到dist[i][j]中去代替函式dist(),枯了還是40/100...
#include<bits/stdc++.h> using namespace std; typedef long long ll; const int V=3005, P=305, inf=0x3f3f3f3f; int v,p,f[V][P],A[V],dist[V][V]; int initdist() { for (int i=1; i<v; i++) for (int j=i+1; j<=v; j++) { dist[i][j]=dist[i][j-1]+A[j]-A[i+j>>1]; } } int main() { std::ios::sync_with_stdio(false); cin.tie(0); cout.tie(0); cin>>v>>p; for (int i=1; i<=v; i++) cin>>A[i]; memset(f, inf, sizeof f); f[0][0]=0; initdist(); for (int j=1; j<=p; j++) //郵局 for (int i=1; i<=v; i++) //村莊 for (int k=0; k<i; k++) { //少量村莊 f[i][j]=min(f[i][j], f[k][j-1]+dist[k+1][i]); } cout << f[v][p]; return 0; }
複雜度分析
- Time:\(O(v^2×p)\),
- Space:\(O(vp)\),