POJ2287 Tian Ji——The Horse Racing

这是一个田忌赛马的故事。
田忌用差的马去匹配齐王的好马,等到田忌的好马能够获胜时,田忌就可以用好马直接赢得比赛。
一开始用了二分图的最大匹配做的,先判断田忌最多能胜多少局,再判断最多不败多少局,用(win+notlose- n)*200即可,但是很显然时间会超出。
再仔细读题,题目中说二分图的方法对于这个问题来说“有点高级”,因此用贪心做即可。
代码1(TLE):二分图的最大匹配

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<ctime>
#include<cstdlib>
#include<map>
#include<queue>
#include<stack>
using namespace std;

typedef long long ll;
int tianji[1010],king[1010];
bool line[1010][1010];
int m;// 双方马匹数量 
int linker[1010];
bool used[1010];

int win,notlose;
bool find(int x)
{
    int i,j;
    for(j=1;j<=m;j++)
    {
        if(line[x][j]==true&&used[j]==false){
            used[j] =1;
            if(linker[j]==0||find(linker[j]))
            {
                linker[j] = x;
                return true;
            }
        }
    }
    return false;
}
int main()
{
    while(scanf("%d",&m),m)
    {
        int win=0;
        memset(line,0,sizeof line);
        memset(linker,0,sizeof linker);
        for(int i =1;i<=m;i++)
            scanf("%d",&tianji[i]);
        for(int j=1;j<=m;j++)
            scanf("%d",&king[j]);
        for(int i=1;i<=m;i++)
        for(int j=1;j<=m;j++)
            if(tianji[i]>king[j])
                line[i][j]=true;
        for(int i =1;i<=m;i++)
        {
            memset(used,0,sizeof(used));
            if(find(i))
            win++;
        }
        //在前面基础上进行改动 
        memset(linker,0,sizeof linker);
        int notlose = 0;
        for(int i=1;i<=m;i++)
        for(int j=1;j<=m;j++)
            if(tianji[i]==king[j])
                line[i][j]=true;
        for(int i =1;i<=m;i++)
        {
            memset(used,0,sizeof(used));
            if(find(i))
            notlose++;
        }
        printf("%d\n",(win-m+notlose)*200);
    } 
    return 0;
}

代码2:(AC)贪心做法:
这里涉及到一个状态的选择摘抄一段思路,原文如下

如果田忌最快的马比国王最快的马要快,那么直接比
如果田忌最快的马比国王最快的马要慢,那么用田忌最慢的马去和国王最快的马比,(反正一定要输一场,而田忌最快的马可能还能在其他比赛中胜出,所以用田忌最慢的去比至少不会吃亏)
如果田忌最快的马和国王最快的马一样快,那么要分情况
A.如果田忌最慢的马的速度小于国王最慢的马,那么就用田忌最慢的马去和国王现在最快的马比(因为田忌最慢的马现在一场也赢不了,所以还不如来抵抗国王最快的,留下自己最快的可能还能在其他比赛中胜出)
B.如果田忌最慢的马速度和国王最慢的马的速度一样,那么此时,我们还是应该用这匹最慢的马去和国王最快的马比(如果是快对快,慢对慢这样比,虽然不会亏,但是田忌最快的马已经用掉,不可能在去盈利,而如果是用田忌最慢的马去和国王最快的马比,虽然这里可能吃亏了,但是存在一种情况,即使田忌最快的马在面对除国王最慢以外的其他马时,无法盈利,但是此时田忌最快的马面对国王最慢的马时,至少不会吃亏,所以2种策略对比,后者更可取,因为除上述情况外, 田忌还是可能获利的)
C. 如果田忌最慢的马的速度大于国王最慢的马,那么就应该用田忌最慢的马去和国王最慢的马比(这里至少可以获利,去除所有C的情况,我们把情况转化为A,B,即使采取A,B策略亏本了(面对国王最快的马然后输掉比赛),C策略下的盈利还是大于等于亏本的)

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstdlib>
using namespace std;

bool cmp(int a,int b)
{
    return a>b;
}

int king[1010],tianji[1010];
int n;
int t1,k1,t2,k2;//通过模拟确定赛马匹配 
int main()
{
    while(scanf("%d",&n),n)
    {
        int win=0; 
        for(int i =0;i<n;i++) 
        scanf("%d",&tianji[i]);
        for(int j=0;j<n;j++)
        scanf("%d",&king[j]);
        sort(tianji,tianji+n,cmp);
        sort(king,king+n,cmp);
        t1=k1=0;t2=k2 = n-1;
        for(int i =0;i<n;i++)
        {
            if(tianji[t1]>king[k1])
            {
                win++;t1++;k1++;
                continue;
            }
            if(tianji[t1]<king[k1])
            {
                win--;
                k1++;
                t2--;
                continue;
            }
            if(tianji[t1]==king[k1])
            {
                if(tianji[t2]>king[k2])
                {
                    win++;k2--;t2--;continue;
                }
                if(tianji[t2]<king[k2])
                {
                    win--;
                    t2--;
                    k1++;
                    continue;
                }
                if(tianji[t2]==king[k2])
                    if(tianji[t2]<king[k1])
                    {
                        win--;
                        t2--;
                        k1++;
                        continue; 
                    }
            }

        }
        printf("%d\n",win*200);
    }
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值