acwing 104.貨倉選址
https://www.acwing.com/problem/content/106/
題意:需要在豎軸上選一個點,使該點到其他給出點的距離之和最小。將其抽象為數學公式$\left | x - c_1 \right |+\left | x-c_2 \right |+\left | x-c_3 \right |+\cdot \cdot \cdot \left | x-c_k \right |$,求該公式的最小值。
可以知道,該公式的最小值就是取$c_1, c_2, c_3,\cdot \cdot \cdot c_k$的中位數。
證明:
當只有一個點的時候,選在該點肯定為最小,當有兩個點的時候,選在兩個點中間的任何一個位置都為最小,當有三個點的時候,選在中間那個點的位置。我們將每個點兩兩分組。
①當$k$為奇數時,$x_1$和$x_k$一組,$x_2$和$x_{k -1}$一組,最后剩$x_{\frac{k + 1}{2}}$單獨一組,可以知道,選擇每一組中間的點都是最小的。而$x_{\frac{k + 1}{2}}$這一組要選在這個點上最小,所以選在$x_{\frac{k + 1}{2}}$上的時候,滿足該組的值最小,也滿足其他組的值最小,所以總和最小。
②當$k$為偶數時,每一組都是兩兩配對,選擇每組中間的位置就最小值,而最靠近中心的兩個點的那個區間,選擇任意一個在該區間內的點,都可以做到使得每一組的答案最小。
思路:讀入一個$a$數組,排序,找出中位數,用所有數減去中位數的絕對值相加即為答案。
1 #include <iostream> 2 #include <algorithm> 3 #include <cstring> 4 5 using namespace std; 6 7 const int N = 1e5+10; 8 int a[N]; 9 int n; 10 11 int main(){ 12 cin >> n; 13 for(int i = 0 ; i < n ; i ++)cin >> a[i]; 14 15 sort(a, a + n); 16 int c = a[n / 2]; 17 18 int res = 0; 19 for(int i = 0 ; i < n ; i ++)res += abs(a[i] - c); 20 21 cout << res << endl; 22 return 0; 23 }
acwing 122.糖果傳遞
https://www.acwing.com/problem/content/description/124/
假設只向前方進行傳遞,設a_1傳遞的個數為x_1, 畫出如圖:
根據圖,我們可以知道我們要求的就是公式$\left |x_1 \right |+\left | x_2 \right |+\cdot \cdot \cdot \left | x_n \right |$的最小值,而且我們可以寫出一組公式
$\left\{\begin{matrix}a_1-x_1+x_2 = \bar{a}
& & & & \\ a_2-x_2+x_3=\bar{a}
& & & & \\ a_3-x_3+x_4=\bar{a}
& & & & \\ \cdot \cdot \cdot
& & & & \\a_n-x_n+x_1=\bar{a}
\end{matrix}\right.$
化簡該公式:
$\left\{\begin{matrix}x_1=x_1 - 0
& & & \\ x_2=x_1-(a_1-\bar{a})
& & & \\ x_3=x_1-(a_1+a_2-2 \bar{a})
& & & \\ x_4 = x_1-(a_1+a_2+a_3 - 3\bar{a})
& & & \\ \cdot \cdot \cdot
& & & \\x_n=x_1-(a_1+a_2+\cdot \cdot \cdot a_{n-1}-(n-1)\bar{a})
\end{matrix}\right.$
可以看出,$x_1$后方的值可以看做常數項,將其設為$c$,
可以將公式再次化為:
$\left\{\begin{matrix}x_1=x_1 -c_1
& & & \\ x_2=x_1-c_2
& & & \\ x_3=x_1-c_3
& & & \\ x_4 = x_1-c_4
& & & \\ \cdot \cdot \cdot
& & & \\x_n=x_1-c_n
\end{matrix}\right.$
這樣,題目就從求$\left |x_1 \right |+\left | x_2 \right |+\cdot \cdot \cdot \left | x_n \right |$的最小值,變成了求$\left |x_1 -c_1 \right |+\left | x_1-c_2 \right |+\cdot \cdot \cdot \left | x_1-c_n \right |$的最小值。轉換為了求絕對值不等式的最小值。
思路:用遞推的方式將數組$c$處理出,然后排序。循環與中位數相減將絕對值相加即為答案。
1 #include <cstdio> 2 #include <cstring> 3 #include <iostream> 4 #include <algorithm> 5 6 using namespace std; 7 8 typedef long long LL; 9 10 const int N = 1000010; 11 12 int n; 13 int a[N]; 14 LL c[N]; 15 16 int main() 17 { 18 scanf("%d", &n); 19 for (int i = 1; i <= n; i ++ ) scanf("%d", &a[i]); 20 21 LL sum = 0; 22 for (int i = 1; i <= n; i ++ ) sum += a[i]; 23 24 LL avg = sum / n; 25 for (int i = n; i > 1; i -- ) 26 { 27 c[i] = c[i + 1] + avg - a[i]; 28 } 29 c[1] = 0; 30 31 sort(c + 1, c + n + 1); 32 33 LL res = 0; 34 for (int i = 1; i <= n; i ++ ) res += abs(c[i] - c[(n + 1) / 2]); 35 36 printf("%lld\n", res); 37 38 return 0; 39 }
acwing 105.七夕祭
https://www.acwing.com/problem/content/107/
分析題意知道,這道題目有一個性質是,只會改變相鄰的兩個數的位置,因此我們交換兩個數,只會改變一行的喜愛小攤或者一列的喜愛小攤,而不會同時改變行和列的喜愛小攤,這樣,我們就可以將這道題目分成兩個部分,一部分是求行的最少次數,一部分是求列的最少次數。這樣原問題就從二維的問題拆成了一維的問題,等於在豎直方向上和水平方向上做糖果傳遞。
1 #include <iostream> 2 #include <algorithm> 3 #include <cstring> 4 5 using namespace std; 6 7 typedef long long LL; 8 9 const int N = 1000010; 10 11 int n, m, T; 12 int col[N], row[N]; 13 int s[N], c[N]; 14 15 LL solve(int n, int r[]) 16 { 17 memset(s, 0, sizeof s); 18 memset(c, 0 ,sizeof c); 19 20 for(int i = 1 ; i <= n ; i ++)s[i] = s[i - 1] + r[i]; 21 22 if(s[n] % n)return -1; 23 24 int avg = s[n] / n; 25 26 for(int i = 2 ; i <= n ; i ++)c[i] = s[i - 1] - (i - 1) * avg; 27 28 sort(c + 1, c + n + 1); 29 30 LL sum = 0; 31 for(int i = 1 ; i <= n ; i ++)sum += abs(c[i] - c[(n + 1) / 2]); 32 33 return sum; 34 } 35 36 int main(){ 37 38 cin >> n >> m >> T; 39 40 while(T --) 41 { 42 int x, y; 43 cin >> x >> y; 44 row[x] ++, col[y] ++; 45 } 46 47 LL one = solve(n, row); 48 LL two = solve(m, col); 49 50 if(one != -1 && two != -1)cout << "both" << " " << one + two << endl; 51 else if(one != -1)cout << "row" << " " << one; 52 else if(two != -1)cout << "column" << " " << two; 53 else cout << "impossible" << endl; 54 55 return 0; 56 }