題目大意
想必大家都做過一道經典的貪心問題:田忌賽馬。
本題的背景與田忌賽馬大致相似:你和對手各有n匹馬,每匹馬都有一個能力值,你和對手每輪選擇一匹自己的未上場的馬進行比賽,當你的馬的能力值大於對方時,你獲得這輪的勝利。
你已知對手每匹馬的出場順序,如何安排你的馬的出場順序,使得自己的勝場最多?
與傳統的貪心題不同的地方是,這次你希望在勝場最多的情況下,給出字典序最大的出場順序(能力值的字典序)。
解題思路
首先,我們要對兩個數組排序(b數組的順序無所謂,不過a數組得存在另一個數組里排序,畢竟a的順序是很有用的)
接着,我們要運用貪心的方法求出最多的勝場。
然后,我們for循環枚舉當前PK的馬,隨后貪心求解
我們貪心的思想就是讓小的去對掉大的,但是我們的代碼中並沒有明顯的這一步。
因為如果當前沒有任何一匹馬能戰勝這匹馬,我們的判斷就會起作用:如果這匹馬不在最大成功匹配中,tot就不會減1
這樣就會符合勝場最多的條件,同時字典序最大。
代碼
#include<bits/stdc++.h>
using namespace std;
int n,k1,k2,k3,tot,a[5050],b[5050],c[5050],bb[5050],cc[5050],v[5050];
bool cmp(int x,int y){return x>y;}
int main()
{
// freopen("horse.in","r",stdin);
// freopen("horse.out","w",stdout);
scanf("%d",&n);
for(int i=1;i<=n;i++)
scanf("%d",&a[i]);
for(int i=1;i<=n;i++)
c[i]=a[i];
for(int i=1;i<=n;i++)
scanf("%d",&b[i]);
sort(c+1,c+n+1,cmp);//從大到小排列敵方的馬的能力值
sort(b+1,b+n+1,cmp);//從大到小排列你的馬的能力值
for(int i=1,j=1;i<=n&&j<=n;j++)//貪心求出最大贏的場數,用tot記錄
if(b[i]>c[j])i++,tot++;
for(int i=1;i<=n;i++)//枚舉PK第幾頭馬
{
memset(v,0,sizeof(v));
k2=k3=0;//清空
//k2:是否贏了敵方的馬
//k3統計的是當前最大的成功匹配數
for(int j=1;j<=n;j++)
if(c[j]==a[i]&&!cc[j]){cc[j]=1;break;}
//cc[j]=1表示c[j]在前i個a中出現過
//v[j]表示最大的成功中有沒有第j個數
for(int j=n,k=n;j&&k;j--)
{
if(bb[j])continue;//這個位有沒有用過
while(k&&cc[k])k--;//前面出現過c[j],直接跳過
if(k&&b[j]>c[k])k--,v[j]=1,k3++;
}
bool f=1;
//f表示的應該是是否要去掉當前這個匹配
for(int j=1;j<=n;j++)//貪心從大到小枚舉
{
if(!bb[j])//沒有被用過
{
if(b[j]>a[i])k2=1;//可以殺死敵方的馬
if(!v[j])f=0;//沒有在最大成功匹配中,不用刪掉
if(k2+k3==tot+f)//選擇這個數后面的答案是否正確
{
printf("%d ",b[j]);//輸出答案
bb[j]=1;//標記成已使用
tot-=k2;//讓tot減去這輪的情況
break;//直接跳出循環
}
}
}
}
return 0;
}