求解田忌赛马问题

问题

问题描述

两千多年前的战国时期,齐威王与大将田忌赛马。双方约定每人各出 300 匹马,并且在上、中、下 3 个等级中各选一匹进行比赛,由于齐威王每个等级的马都比田忌的马略强,比赛的结果可想而知。现在双方各 n 匹马,依次派出一匹马进行比赛,每一轮获胜的一方将从输的一方得到 200 银币,平局则不用出钱,田忌已知所有马的速度值并可以安排出场顺序,问他如何安排比赛获得的银币最多?

Tip: 本题为单组输入

输入描述

image

输出描述

每个测试用例输出一行,表示田忌获得的最多银币数。

样例输入

3
92 83 71
95 87 74

样例输出

200

思考

ppt复读机


贪心算法

先分别把田忌和齐威王的马按速度由低到高排序。

可以分为以下几种情况:

1.田忌最快的马比齐威王最快的马慢,此时用田忌最慢的马和齐威王最快的马比,失败+1
2.田忌最快的马比齐威王最快的马快,此时用田忌最快的马和齐威王最快的马比,胜利+1
3.田忌最快的马和齐威王最快的马一样快,此时问题继续考虑以下情况

1.田忌最慢的马比齐威王最慢的马快,此时用田忌最慢的马和齐威王最慢的马比,胜利+1
2.田忌最慢的马比齐威王最慢的马慢/一样慢,此时用田忌最慢的马和齐威王最快的马比,如果田忌最慢的马比齐威王最快的马慢,失败+1,否则平局

最初我对3.2的情况不能理解,想不通为什么要加一条如果田忌最慢的马比齐威王最快的马慢,失败+1的判断,既然田忌最快的马和齐威王最快的一样快,那么田忌最慢的马不是理所应当的比齐威王最快的马慢吗?直接失败+1不就欧克了。后来,发现自己忽略了一种情况,那就是如果田忌的马速度都一样,那么此时田忌最慢的马不也和齐威王最快的马速度相同了吗,这是就是平局。

代码

点击查看代码
#include <iostream>
using namespace std;

int competition(int *a, int *b, int s1, int t1, int s2, int t2);
//快速排序
void QuickSort(int a[], int s, int t);
int Partition(int a[], int s, int t);
int main()
{
	int n; //马的数量
	cin >> n;
	int *tianji = new int[n]; //田忌的马的速度
	int *qiwei = new int[n];  //齐威王的马的速度
	for (int i = 0; i < n; i++)
		cin >> tianji[i];
	for (int i = 0; i < n; i++)
		cin >> qiwei[i];
	//为马按马的速度由低到高排序
	QuickSort(tianji, 0, n - 1);
	QuickSort(qiwei, 0, n - 1);
	cout << competition(tianji, qiwei, 0, n - 1, 0, n - 1) << endl;

	return 0;
}
// a[...]田忌的马
// b[...]齐威王的马
int competition(int *a, int *b, int s1, int t1, int s2, int t2)
{
	int coin = 0; //银币数量
	while (s1 <= t1)
	{
		//田忌最快的马比齐威王最快的马还慢
		//用田忌最慢的马和齐威王最快的马比
		if (a[t1] < b[t2])
		{
			coin -= 200; //输了200银币
			t2--;		 //齐威王目前最快的马参加了比赛
			s1++;		 //田忌目前最慢的马参加了比赛
		}
		//田忌最快的马比齐威王最快的马还慢
		//用田忌最快的马和齐威王最快的马比
		else if (a[t1] > b[t2])
		{
			coin += 200; //赢了200银币
			t1--;		 //田忌目前最快的马参加了比赛
			t2--;		 //齐威王目前最快的马参加了比赛
		}
		//田忌最快的马与齐威王最快的马马速相等
		//再分3种情况
		else
		{
			//田忌最慢的马比齐威王最慢的马快
			//用田忌最慢的马和齐威王最慢的马比
			if (a[s1] > b[s2])
			{
				coin += 200;
				s1++;
				s2++;
			}
			// 田忌最慢的马比齐威王最慢的马慢/相等
			else
			{
				//田忌最慢的马比齐威王最快的马慢
				if (a[s1] < b[t2])
					coin -= 200;
				s1++;
				t2--;
			}
		}
	}
	return coin;
}

void QuickSort(int a[], int s, int t)
{
	//对a[s....t]元素进行递增排序
	if (s < t)
	{
		int i = Partition(a, s, t);
		QuickSort(a, s, i - 1);
		QuickSort(a, i + 1, t);
	}
}

int Partition(int a[], int s, int t)
{
	int i = s, j = t;
	int temp = a[s]; //用第一个记录作为基准
	while (i != j)	 //从序列两端交替向中间扫描,直到i=j为止
	{
		while (j > i && a[j] >= temp)
			j--; //从右向左扫描,找到第一个小于temp的a[j]
		a[i] = a[j];
		while (i < j && a[i] <= temp)
			i++; //从右向左扫描,找到第一个大于temp的a[i]
		a[j] = a[i];
	}
	a[i] = temp;
	return i;
}

posted @ 2022-04-05 16:24  请去看诡秘之主  阅读(317)  评论(0)    收藏  举报