贪心系列-田忌赛马模型

1 篇文章 0 订阅

心路历程是这样纸的:

翻到一道bzoj的题,泡泡堂BNB,恩,题意很简单,就像田忌赛马那样dp一下就好了,可是dp是n^2的,这里的数据变成了10W,怎么办?

瞬间懵逼~懵逼~~


翻了一下田忌赛马那道题,考虑了一下dp,看能不能优化:

这样dp的:

现将两个人的马从大到小排序

定义f[i][j]表示对于齐王的前i强的马,用了前j强的马和i-j弱的马获得的最大利益。

f[i][j]=max(f[i-1][j-1]+g[i][j],f[i-1][j]+g[i][n-(i-j)+1]);        g[i][j]表示齐王的第i强和田忌的第j强相比,田忌的获利。

还是一个n^2的dp,n(n-1)/2,对于10W是跑不下的呀!


然后懵逼了,猜测也许会用贪心,but不会贪


然后求助网上的题解- - -- - - - -- - - -- - - 


网上是这么搞的:

也是先排序,然后考虑田忌的当前最强的马和齐王最强的马相比:

如果田忌马强,直接比,因为这匹马一定会赢,不如赢掉能赢掉的最强的。

如果弱,用田忌最弱的,因为反正会输,不如用最差的消耗掉最强的。

如果平:

   1.田忌最弱的比齐王最弱的强,比赛过去,因为齐王的那匹弱马一定会输,不如用最差的赢掉。

   2.其他情况,用田忌最弱的和期望最强的比,要么输要么平。

   (为什么这样做是最优的?考虑3匹马,如果发生了这种情况,这么做一定不会最差)


然后就代码了。



然后类比田忌赛马的贪心,bzoj1034也可以做了:

#include<cstdio>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<queue>
#include<cmath>
using namespace std;
const int maxn=100000+20;
/*
按实力值从大到小排序 
感觉有点像田忌赛马,在最好情况的时候,定义f[i][j]表示选了前 
*/
int n;
int mi[maxn],dui[maxn];
bool cmp(int x,int y)
{
	return x>y;
}
int work(int *ti,int *qi)
{
	int ans=0;
	int h1=1,t1=n,h2=1,t2=n;
	for(int i=1;i<=n;i++)
	{
		if(ti[h1]>qi[h2])
		{
			ans+=2;
			h1++;
			h2++;
		}
		else if(ti[h1]<qi[h2])
		{
			t1--;
			h2++;
		}
		else
		{
			if(ti[t1]>qi[t2])
			{
				ans+=2;
				t1--;
				t2--;
			}
			else
			{
				if(ti[t1]==qi[h2])ans++;
				t1--;
				h2++;
			}
		}
	}
	return ans;
}
int best()
{
	return work(mi,dui);
}
int worst()
{
	return 2*n-work(dui,mi);
}
int main()
{
	scanf("%d",&n);
	for(int i=1;i<=n;i++)scanf("%d",&mi[i]);
	for(int i=1;i<=n;i++)scanf("%d",&dui[i]);
	sort(mi+1,mi+n+1,cmp);
	sort(dui+1,dui+n+1,cmp);
	printf("%d %d\n",best(),worst());
	return 0;
}


  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值