贪心算法_排队不等式_绝对值不等式_推公式

排队不等式

原题链接

https://www.acwing.com/problem/content/915/

题目大意:

有 n 个人排队到 1 个水龙头处打水,第 i 个人装满水桶所需的时间是 ti,请问如何安排他们的打水顺序才能使所有人的等待时间之和最小?

思路:

从小到大排序,时间短的人先打水。

证明:

假设总时间为 r e s = t 1 ( n − 1 ) + t 2 ( n − 2 ) + . . . + t n ( n − n ) res = t_1(n-1)+t_2(n-2)+...+t_n(n-n) res=t1(n1)+t2(n2)+...+tn(nn),如果res是最优解,一定有 t i < = t i + 1 t_i<=t_{i+1} ti<=ti+1
反证法:
如果 t i > t i + 1 t_i>t_{i+1} ti>ti+1,交换 t i t_i ti t i + 1 t_{i+1} ti+1的打水顺序。
交换前: r e s 1 = . . . + t i ( n − i ) + t i + 1 ( n − i − 1 ) + . . . res_1 = ...+t_i(n-i)+t_{i+1}(n-i-1)+... res1=...+ti(ni)+ti+1(ni1)+...
交换后: r e s 2 = . . . + t i + 1 ( n − i ) + t i ( n − i − 1 ) + . . . res_2 = ...+t_{i+1}(n-i)+t_i(n-i-1)+... res2=...+ti+1(ni)+ti(ni1)+...
a n s = r e s 1 − r e s 2 = t i − t i + 1 > 0 ans = res1-res2=t_i-t_{i+1}>0 ans=res1res2=titi+1>0,所以交换后总时间会变少,说明 r e s 1 res_1 res1不是最优解。

代码:

#include<iostream>
#include<algorithm>

using namespace std;

typedef long long LL;

const int N = 1e5+5;

int a[N];

int main(){
    
    
    int n;
    cin>>n;
    for(int i=0;i<n;i++){
    
    
        scanf("%d",&a[i]);
    }
    
    sort(a,a+n);
    
    LL res=0;
    for(int i=0;i<n;i++){
    
    
        res+=a[i]*(n-1-i);
    }
    
    cout<<res<<endl;
    return 0;
}

绝对值不等式

原题链接

https://www.acwing.com/problem/content/106/

题目大意:

在一条数轴上有 N 家商店,它们的坐标分别为 A 1 ∼ A N A_1∼A_N A1AN
现在需要在数轴上建立一家货仓,每天清晨,从货仓到每家商店都要运送一车商品。
为了提高效率,求把货仓建在何处,可以使得货仓到每家商店的距离之和最小。

思路:

找n个点的中位数,这个数就是距离的最小值点。

证明:

r e s = ∣ x 1 − x 0 ∣ + ∣ x 2 − x 0 ∣ + . . . + ∣ x 1 − x n ∣ , x i res=|x_1-x_0|+|x_2-x_0|+...+|x_1-x_n|,x_i res=x1x0+x2x0+...+x1xn,xi表示商店位置 ( x i < x i + 1 ) (x_i<x_{i+1}) (xi<xi+1) x 0 x_0 x0表示货仓的位置。
若商店数量为偶数家: r e s = ( ∣ x 1 − x 0 ∣ + ∣ x n − x 0 ∣ ) + . . . + ( ∣ x n 2 − x n ∣ + ∣ x n + 1 2 ∣ ) res=(|x_1-x_0|+|x_n-x_0|)+...+(|x_{\frac n 2}-x_n|+|x_{\frac {n+1}2}|) res=(x1x0+xnx0)+...+(x2nxn+x2n+1)
若商店数量为奇数家: r e s = ( ∣ x 1 − x 0 ∣ + ∣ x n − x 0 ∣ ) + . . . + ∣ x n 2 − x 0 ∣ res=(|x_1-x_0|+|x_n-x_0|)+...+|x_{\frac n 2}-x_0| res=(x1x0+xnx0)+...+x2nx0
若要res最小,只需要让括号内的每个数都最小,而 ∣ x i − x 0 ∣ + ∣ x j − x 0 ∣ |x_i-x_0|+|x_j-x_0| xix0+xjx0 x 0 x_0 x0取值在 [ x i , x j ] [x_i,x_j] [xi,xj]这个区间时,取到最小值。而由于 ( x i < x i + 1 ) (x_i<x_{i+1}) (xi<xi+1),所以 [ x i , x n − i ] [x_i,x_{n-i}] [xi,xni]这个区间一定包括在 [ x i − 1 , x n − i + 1 ] [x_{i-1},x_{n-i+1}] [xi1,xni+1]这个区间当中。
所以最终如果n是偶数,则 x 0 x_0 x0 [ x n 2 , x n + 1 2 ] [x_{\frac n 2},x_{\frac {n+1}2}] [x2n,x2n+1]这个区间当中的任意一个点。
如果n是奇数,则 x 0 x_0 x0 x n 2 x_{\frac n 2} x2n这个点。

代码:

#include<iostream>
#include<algorithm>

using namespace std;

typedef long long LL;

const int N = 1e5+5;

int a[N];
int n;

int main(){
    
    
    cin>>n;
    for(int i=0;i<n;i++){
    
    
        scanf("%d",&a[i]);
    }
    
    sort(a,a+n);
    
    LL res=0;
    for(int i=0;i<n;i++) res+=abs(a[i]-a[n/2]);
    
    cout<<res<<endl;
    return 0;
}

推公式

原题链接

https://www.acwing.com/problem/content/127/

题目大意

农民约翰的 N 头奶牛(编号为 1…N)计划逃跑并加入马戏团,为此它们决定练习表演杂技。奶牛们不是非常有创意,只提出了一个杂技表演:叠罗汉
表演时,奶牛们站在彼此的身上,形成一个高高的垂直堆叠。奶牛们正在试图找到自己在这个堆叠中应该所处的位置顺序。这 N头奶牛中的每一头都有着自己的重量 Wi 以及自己的强壮程度 Si。
一头牛支撑不住的可能性取决于它头上所有牛的总重量(不包括它自己)减去它的身体强壮程度的值,现在称该数值为风险值,风险值越大,这只牛撑不住的可能性越高。
您的任务是确定奶牛的排序,使得所有奶牛的风险值中的最大值尽可能小。

思路:

根据w[i]+s[i]的值从小到大排序,总和最小的牛叠在最上面。算最大的风险数。

证明:

设x为我们算出的解,ans为最优解。
1.证明x>=ans
因为x是可行解,所以x一定>=ans
2.证明x<=ans
设存在i使得, s [ i ] + w [ i ] > s [ i + 1 ] + w [ i + 1 ] s[i]+w[i]>s[i+1]+w[i+1] s[i]+w[i]>s[i+1]+w[i+1]
已知:
i和i+1位置的牛在交换前:
第i号位置的牛的风险指数是: w [ 0 ] + w [ 1 ] + . . . + w [ i − 1 ] − s [ i ] w[0]+w[1]+...+w[i-1]-s[i] w[0]+w[1]+...+w[i1]s[i]
第i+1号位置的牛的风险指数是: w [ 0 ] + w [ 1 ] + . . . + w [ i ] − s [ i + 1 ] w[0]+w[1]+...+w[i]-s[i+1] w[0]+w[1]+...+w[i]s[i+1]
i和i+1位置的牛在交换后:
第i号位置的牛的风险指数是: w [ 0 ] + w [ 1 ] + . . . + w [ i − 1 ] − s [ i + 1 ] w[0]+w[1]+...+w[i-1]-s[i+1] w[0]+w[1]+...+w[i1]s[i+1]
第i+1号位置的牛的风险指数是: w [ 0 ] + w [ 1 ] + . . . + w [ i − 1 ] + w [ i + 1 ] − s [ i ] w[0]+w[1]+...+w[i-1]+w[i+1]-s[i] w[0]+w[1]+...+w[i1]+w[i+1]s[i]
因为我们比较的是风险指数的最大值,所以可以对上式同时进行变换。同时减去 ( w [ 0 ] + w [ 1 ] + . . . + w [ i − 1 ] − s [ i ] − s [ i + 1 ] ) (w[0]+w[1]+...+w[i-1]-s[i]-s[i+1]) (w[0]+w[1]+...+w[i1]s[i]s[i+1])
i和i+1位置的牛在交换前:
第i号位置的牛的风险指数是: s [ i + 1 ] s[i+1] s[i+1]
第i+1号位置的牛的风险指数是: w [ i ] + s [ i ] w[i]+s[i] w[i]+s[i]
i和i+1位置的牛在交换后:
第i号位置的牛的风险指数是: s [ i ] s[i] s[i]
第i+1号位置的牛的风险指数是: w [ i + 1 ] + s [ i + 1 ] w[i+1]+s[i+1] w[i+1]+s[i+1]
因为 w [ i ] + s [ i ] > w [ i + 1 ] + s [ i + 1 ] w[i]+s[i]>w[i+1]+s[i+1] w[i]+s[i]>w[i+1]+s[i+1]并且 w [ i ] + s [ i ] > s [ i ] w[i]+s[i]>s[i] w[i]+s[i]>s[i],所以在交换位置后,风险最大值一定变小了。所以x一定比所有的解都要小。
因为 a n s < = x < = a n s ans<=x<=ans ans<=x<=ans,所以 x = = a n s x==ans x==ans
证毕。

代码:

#include<iostream>
#include<algorithm>

using namespace std;

typedef pair<int, int> PII;

const int N = 50005;

int n;
PII cow[N];

int main() {
    
    
    cin >> n;
    for (int i = 0; i < n; i++) {
    
    
        int w, s;
        scanf("%d%d", &w, &s);
        cow[i] = {
    
     w + s,w };
    }

    sort(cow, cow + n);

    int res = -2e9, sum = 0;
    for (int i = 0; i < n; i++) {
    
    
        int w = cow[i].second, s = cow[i].first - w;
        res = max(res, sum - s);
        sum+=w;
    }
    cout << res << endl;
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_45931661/article/details/120110445