田忌賽馬 題解


題目大意

想必大家都做過一道經典的貪心問題:田忌賽馬。
本題的背景與田忌賽馬大致相似:你和對手各有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;
}


免責聲明!

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



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