HRBUST - 2319 Number Game(贪心+DP | 贪心+优先队列)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/chimchim04/article/details/89532128

Number Game

There are n items and two players, Kim and you. For each player and for each item, the value of the item for this player is known. Denote values of the i-th item for the first and the second player as ai and bi correspondingly.

Players take the items in turns. Kim starts the game. Kim is greedy: each turn, he chooses the item which has the maximal ai among the remaining items. If there are several such items, he can take any one of them. What is the maximal possible sum of values bi of items taken by the second player that he can guarantee regardless of the first player’s moves?

Input

The first line is an integer T, describes the number of tests. Then T tests.

Each case contains a single integer n, the number of items.

The second line contains n numbers, i-th is equal to ai, the value of the i-th item for Kim.

The third line contains n numbers, i-th is equal to bi, the value of the i-th item for the second player.

Output

Output a single number: the maximal sum of values bi of items taken by the second player that he can guarantee.

Sample Input

1
5
1 2 3 4 5
2 3 4 5 6

Sample Output

8

Hint

1 <= n <= 1000

ai and bi are integers from 1 to 10e9

题目大意:

有n个物品,每个物品对于a和b的价值是不一样的,第i个物品对a的价值是ai,对b的价值是bi

现在a b 轮流取物品,a先取,a取的要求是每一次取剩下物品中对于a来说价值最大的,如果有多个价值相同的,可以任意取一个,但是我们要求最后b取得的物品最大总价值,不管a怎么取,都能保证的最大值,所以当ai相同时,我们让a取其中bi最大的那个

思路:先对物品排序,按照ai从大到小,如果ai相等bi从大到小,排完序后因为第一个物品无论如果都会被a取走,所以不管它,对剩下的物品DP,剩下的物品是n-1个,可以确定的是:其中a会取走 k =(n-1)/2个 ,b会取走k1=n-1-k个,b先取

dp [ i ] [ j ] 表示在前 i+j 个物品中,b取走i个物品的最大总价值

状态转移方程:dp[i][j]=max(dp[i-1][j]+e[i+j].b,dp[i][j-1]);

对于前i+j个物品,b取 i 个的状态,可以是前i+j-1个物品中选i-1个,再取走第i+j个,  或者在前i+j-1个物品中取走i个

把其中大的转移过来就行了

从dp[0][0]开始到dp[k1][k] 其中并不是所有状态都存在的,因为我们要保证a每次都能取到最大的所以b取的次数不能比a取的次数大超过一,即 i-j>1  ,其中当i==0时,i-1为负数,不存在这种状态,所以状态只能从j-1传过来, 那么相对的j==0的时候,状态也只能从i-1传过来,还有一种状况是i-j==1的时候也是只能从j-1传过来,最后的DP过程就是:

dp[0][0]=(ll)0; 
        for(ll i=0;i<=k1;i++)
            for(ll j=0;j<=k;j++)
        {
            if(i==0&&j==0) continue;
            else if(i-j>1) continue;
            else if(i==0) dp[i][j]=dp[i][j-1];
            else if(i-j==1) dp[i][j]=dp[i-1][j]+e[i+j].b;
            else dp[i][j]=max(dp[i-1][j]+e[i+j].b,dp[i][j-1]);
        }

如果还是不理解,可以看下面的图:根据样例,k1=k=2,红色的线为边界,箭头为转态转移的方向

代码:

#include<stdio.h>
#include<string.h>
#include<queue>
#include<algorithm>
using namespace std;
#define ll long long
const int N=10005;
struct node
{
    ll a,b;
} e[N];
bool cmp(node x,node y)
{
    if(x.a==y.a) return x.b>y.b;
    return x.a>y.a;
}
ll dp[1005][1005];
int main()
{
    ll t,n;
    scanf("%lld",&t);
    while(t--)
    {
        scanf("%lld",&n);
        for(int i=0; i<n; i++) scanf("%lld",&e[i].a);
        for(int i=0; i<n; i++) scanf("%lld",&e[i].b);
        sort(e,e+n,cmp);
        ll k=(n-1)/2,k1;
        if((n-1)%2) k1=k+1;
        else k1=k;
        dp[0][0]=(ll)0;
        for(ll i=0;i<=k1;i++)
            for(ll j=0;j<=k;j++)
        {
            if(i==0&&j==0) continue;
            else if(i-j>1) continue;
            else if(i==0) dp[i][j]=dp[i][j-1];
            else if(i-j==1) dp[i][j]=dp[i-1][j]+e[i+j].b;
            else dp[i][j]=max(dp[i-1][j]+e[i+j].b,dp[i][j-1]);
        }
        printf("%lld\n",dp[k1][k]);
    }
    return 0;
}

也可以用优先队列模拟选择的过程:

代码:

#include<stdio.h>
#include<string.h>
#include<queue>
#include<algorithm>
using namespace std;
const int N=10005;
struct node
{
    int a,b;
} e[N];
bool cmp(node x,node y)
{
    if(x.a==y.a) return x.b>y.b;
    return x.a>y.a;
}
int main()
{
    int t,n;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d",&n);
        for(int i=0; i<n; i++) scanf("%d",&e[i].a);
        for(int i=0; i<n; i++) scanf("%d",&e[i].b);
        sort(e,e+n,cmp);
        priority_queue< int, vector<int>,greater<int> >q; //从小到大排序
        for(int i=0; i<n; i++)
        {
            if(i%2==1) q.push(e[i].b);
            else
            {
                if(!q.empty()&&q.top()<e[i].b)
                {
                    q.pop();
                    q.push(e[i].b);
                }
            }
        }
        long long sum=0;
        while(!q.empty())
        {
            sum+=(long long)q.top();
            q.pop();
        }
        printf("%lld\n",sum);
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/chimchim04/article/details/89532128