第一章-問題求解策略-LA3266-Tian Ji -- The Horse Racing

分類:貪心
題目鏈接:LA3266-Tian Ji – The Horse Racing
經典貪心問題

【問題描述】大家都知道“田忌賽馬”的故事。現在,田忌再一次和齊王賽馬。他們各派出N匹馬(N≤2000)。每場比賽,輸的一方將要給贏的一方200兩黃金,如果是平局的話,雙方都不必拿出錢。
每匹馬的速度值是固定而且已知的,而齊王出馬也不管田忌的出馬順序。請問田忌該如何安排自己的馬去對抗齊王的馬,才能贏最多的錢?

【分析】[ 選自黃勁鬆《貪婪的動態規劃》,有改動。]
題目本身已經告訴我們怎樣用二分圖最佳匹配來解決這個問題——把田忌的馬放左邊,把齊王的馬放右邊,田忌的馬A和齊王的B之間,如果田忌的馬勝,則連一條權爲200的邊;如果平局,則連一條權爲0的邊;如果輸,則連一條權爲-200的邊。
但是題目告訴我們沒有必要這樣做,我們也無法這樣做(複雜度很高,無法承受N=2000的規模)。

我們不妨用貪心思想來分析一下問題。因爲田忌掌握有比賽的“主動權”,他總是根據齊王所出的馬來分配自己的馬,所以這裏不妨認爲齊王的出馬順序是按馬的速度從高到低出的。由這樣的假設,我們歸納出如下貪心策略:

  1. 如果田忌剩下的馬中最強的馬都贏不了齊王剩下的最強的馬,那麼應該用最差的一匹馬去輸給齊王最強的馬。
  2. 如果田忌剩下的馬中最強的馬可以贏齊王剩下的最強的馬,那就用這匹馬去贏齊王剩下的最強的馬。
  3. 如果田忌剩下的馬中最強的馬和齊王剩下的最強的馬打平,可以選擇打平或者用最差的馬輸掉比賽。 我們發現,第三個貪心策略出現了一個分支:打平或輸掉。如果窮舉所有的情況,算法的複雜度將比求二分圖最佳匹配還要高;如果一概而論的選擇讓最強的馬去打平比賽或者是讓最差的馬去輸掉比賽,則存在反例。
    雖然因爲第三個貪心出現了分支,我們不能直接的按照這種方法來設計出一個完全貪心的方法,但是通過上述的三種貪心策略,我們可以發現,如果齊王的馬是按速度排序之後,從高到低被派出的話,田忌一定是將他馬按速度排序之後,從兩頭取馬去和齊王的馬比賽。有了這個信息之後,動態規劃的模型也就出來了!
    設f(i,j)表示田忌從“頭”取了i匹較強的馬,從“尾”取了j匹較弱的馬進行比賽所能夠得到的最大盈利,則狀態轉移方程爲:f(i,j)=max{
    f(i,j-1)+g[n-(j-1)], f(i-1,j)+g(i)}
    其中g(x)表示田忌的第x匹馬和齊王的第i+j匹馬(此時正是第i+j場比賽)分別按照由強到弱的順序排序之後,田忌所能取得的盈利,勝爲200,輸爲-200,平爲0。
    ------摘自《NOIP複習資料》
#include<cstdio>  
#include<cstdlib>  
#include<cstring>  
#include<cmath>  
#include<algorithm>  
using namespace std;  
const int maxn=1005;  
  
int tj[maxn], qw[maxn];  
  
int main()  
{  
    int n, i, res, max1, max2, min1, min2, cnt;  
    while(~scanf("%d", &n) && n)  
    {  
        for(i=0; i<n; i++)  
            scanf("%d", &tj[i]);  
        for(i=0; i<n; i++)  
            scanf("%d", &qw[i]);  
        sort(tj, tj+n);  
        sort(qw, qw+n);  
  
        res=0;  
        max1=max2=n-1;  
        min1=min2=0;  
        cnt=0;  
        while((cnt++)<n)  
        {  
            if(tj[max1]>qw[max2])  
            {  
                res += 200;  
                max1--;  
                max2--;  
            }  
            else if(tj[max1]<qw[max2])  
            {  
                res -= 200;  
                min1++;  
                max2--;  
            }  
            else  
            {  
                if(tj[min1]>qw[min2])  
                {  
                    res += 200;  
                    min1++;  
                    min2++;  
                }  
                else  
                {  
                    if(tj[min1]<qw[max2]) res -= 200;  
                    min1++;  
                    max2--;  
                }  
            }  
        }  
        printf("%d\n", res);  
    }  
    return 0;  
}  
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章