絕對值不等式


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 }

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM