信息学奥赛一本通 1319:【例6.1】排队接水 | 洛谷 P1223 排队接水
【題目鏈接】
ybt 1319:【例6.1】排隊接水
洛谷 P1223 排隊接水
【題目考點】
1. 貪心
2. 貪心選擇性質(zhì)的證明
要想證明貪心選擇可以得到最優(yōu)解,只需要證明最優(yōu)解包含每一次的貪心選擇。
使用數(shù)學(xué)歸納法:
【解題思路】
1. 證明貪心選擇性質(zhì)
貪心選擇:每次選擇接水時間最短的人去接水
貪心選擇性質(zhì)的證明:
設(shè)n個人的編號為1,2,3,…,n
接水時長最短的人編號為ggg,其接水時間為TgT_gTg?
使用反證法:假設(shè)對于所有最優(yōu)解,第一個接水的人都不可以是貪心選擇得到的人g。
則對于某種最優(yōu)解,其接水順序為d1,d2,...,dnd_1,d_2,...,d_nd1?,d2?,...,dn?,假設(shè)g是第m個接水的人,即dm=g(m>1)d_m = g (m > 1)dm?=g(m>1),記第1個接水的人的編號為a,即d1=ad_1 = ad1?=a
由于g的所有人中打水時間最短的人,那么一定有Ta>TgT_{a} > T_{g}Ta?>Tg?
如果交換aaa與ggg,考慮總接水時間的變化:
- 從d2~dm?1d_2\sim d_{m-1}d2?~dm?1?一共m?2m-2m?2個人,每人等待的時間減少了TaT_aTa?增加了TgT_gTg?,總減少時間為(m?2)(Ta?Tg)(m-2)(T_a-T_g)(m?2)(Ta??Tg?)
- g等待的時間從Ta+∑i=2m?1TdiT_a+\sum_{i=2}^{m-1}T_{di}Ta?+∑i=2m?1?Tdi?變?yōu)?span id="ozvdkddzhkzd" class="katex--inline">000,等待時間減少Ta+∑i=2m?1TdiT_a+\sum_{i=2}^{m-1}T_{di}Ta?+∑i=2m?1?Tdi?
- a的等待時間從000變?yōu)?span id="ozvdkddzhkzd" class="katex--inline">Tg+∑i=2m?1TdiT_g+\sum_{i=2}^{m-1}T_{di}Tg?+∑i=2m?1?Tdi?,等待時間減少?(Tg+∑i=2m?1Tdi)-(T_g+\sum_{i=2}^{m-1}T_{di})?(Tg?+∑i=2m?1?Tdi?)
- 總減少的等待時間為上面三者的加和,結(jié)果為(m?1)(Ta?Tg)(m-1)(T_a-T_g)(m?1)(Ta??Tg?)。由于m>1m>1m>1且Ta>TbT_a>T_bTa?>Tb?,那么(m?1)(Ta?Tg)>0(m-1)(T_a-T_g) > 0(m?1)(Ta??Tg?)>0
因此,如果交換a與g,總接水時間會減少。這與當(dāng)前解是可以使平均接水時間最小的最優(yōu)解相矛盾,因而原命題得證。
證明方法與上面第1點的證明方法類似,把證明中的“第一個接水的人”改為“第k+1個接水的人”即可,不再贅述。
以上證明了該問題具有貪心選擇性質(zhì),即每次選擇接水時間最短的人去接水,可以使n個人的平均等待時間最小。
2. 具體做法
結(jié)構(gòu)體中保存人的編號和打水時間,按打水時間升序?qū)Y(jié)構(gòu)體對象進行排序。計算所有人的等待時間加和,最后除以總?cè)藬?shù)。
3. 排序方法
該題說當(dāng)時間重復(fù)時,按照輸入順序輸出。雖然它說“用sort是可以的”,但嚴(yán)格來講,這里按照輸入順序?qū)⑵浼尤霐?shù)組中,而后按照打水時間進行排序。如要讓相同打水時間的元素保持輸入時的先后順序,則理論上必須選用穩(wěn)定的排序算法。所以這里我們使用stable_sort進行排序。
【題解代碼】
解法1:貪心,使用stable_sort進行排序
#include<bits/stdc++.h> using namespace std; #define N 1005 struct Time {double t;int i;//t:時間 i:人的編號 }; Time a[N]; bool cmp(const Time &a, const Time &b) {return a.t < b.t; } int main() {int n;double sumTime = 0, waitTime = 0;cin >> n;for(int i = 1; i <= n; ++i){cin >> a[i].t;a[i].i = i;}stable_sort(a+1, a+1+n, cmp);for(int i = 1; i <= n; ++i){sumTime += waitTime;//waitTime:當(dāng)前這個人已經(jīng)等的時間 waitTime += a[i].t;cout << a[i].i << ' ';}cout << endl << fixed << setprecision(2) << sumTime / n; return 0; }解法2:貪心 手寫歸并排序
#include<bits/stdc++.h> using namespace std; #define N 1005 struct Time {double t;int i;//t:時間 i:第幾個 }; Time a[N], t[N]; void mergeSort(int l, int r)//歸并排序 {if(l >= r)return;int mid = (l+r)/2;mergeSort(l, mid);mergeSort(mid+1, r);int i = l, j = mid+1, ti = l;while(i <= mid && j <= r){if(a[i].t < a[j].t)t[ti++] = a[i++];elset[ti++] = a[j++];}while(i <= mid)t[ti++] = a[i++];while(j <= r)t[ti++] = a[j++];for(int k = l; k <= r; ++k)a[k] = t[k]; } int main() {int n;double sumTime = 0, waitTime = 0;cin >> n;for(int i = 1; i <= n; ++i){cin >> a[i].t;a[i].i = i;}mergeSort(1, n);for(int i = 1; i <= n; ++i){sumTime += waitTime;//waitTime:當(dāng)前這個人已經(jīng)等的時間 waitTime += a[i].t;cout << a[i].i << ' ';}cout << endl << fixed << setprecision(2) << sumTime / n; return 0; }總結(jié)
以上是生活随笔為你收集整理的信息学奥赛一本通 1319:【例6.1】排队接水 | 洛谷 P1223 排队接水的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: java 反射 类名_java – 从
- 下一篇: 信息学奥赛一本通 1245:不重复地输出