( 其他算法与技巧 )【 田忌赛马问题 】

( 其他算法与技巧 )【 田忌赛马问题 】

选手A的马,顺序和能力都是明确的。

选手B的马,能力是明确的,问如何安排出场顺序可以赢下更多的场次。

以前一直是枚举来做,就是按照 B 选手最差的 i 匹马去输给 A 选手最强的马,其他的再比较。

但是代码很难实现,不是很简洁。

今天新学的方式,先对两个选手的马从小到大排序,i 指针指向A选手第一个,j 指针指向B选手第一个,当 j 指向的马大于 i 指向的马说明可以赢,i++,j++,ans++ ; 否则,j 这匹马谁也赢不了,只能去输,j++.

    // 前提是B选手可以派出马去迎战A选手的任意马。就是B有主动权
    int n,ans=0;cin>>n;
    for ( int i=0; ia[i] ) {
            i++; j++;ans++;
        }
        else j++;
    }
    cout << ans << endl; // B能赢得最大局数

例题:Gym - 102082K 

题意:AB选手都有n批马。给出A选手的马的能力值和出场顺序。给出B选手的马的能力值。问怎么安排B选手的出场顺序才能保证B选手赢下的场次最多。场次一样的的排序输出字典序较大的。

思路:根据上面的讲解,很容易能得到可以赢下的最大场次,排序方式如果是任意的话也可以很容易得到。但是要求字典序最大,这是这道题的难点。

这是一个在某个条件下找最大的情况。一般用二分来做。for循环 第 i 批马 ,二分b序列,check b序列的第 j 批马如果和 i 批马匹配,剩下的马是否还能保证赢下的场次最多。

代码:

#include
#define int long long

using namespace std;

int n;
vector a,b;
int A[5005],B[5005],ans;
vector tb,ta;
int v[5005],pre;

int check()
{
    int now = 0;
    for ( int i=0,j=0; ita[i] ) {
            i++; j++;now++;
        }
        else j++;
    }
    return now;
}

signed main()
{
    cin>>n;
    for ( int i=0; iA[i] ) {
            i++; j++;ans++;
        }
        else j++;
    }
    for ( int i=0; i

 

 

 

 

 

你可能感兴趣的:(算法树之其他算法与技巧)