现在的位置: 首页 > 综合 > 正文

SGU 366 Computer Game 预处理 + POJ1015 dp

2018年04月25日 ⁄ 综合 ⁄ 共 2015字 ⁄ 字号 评论关闭

题意:有n(1<=n<=60000)个选手,每个选手有两个属性a b(0<=a b<=50),现在想选出k(1<=n<=20)个选手,使得这些选手的ABS(sum a - sum b)最小,

         如果存在多种解找到sum a + sum b最大的输出方案。

题解:因为a b很小,那么每个a-b只保留钱k个a+b最大的选手,这样一共最多有2000个选手,然后类似POJ1015搞一个dp即可。


Sure原创,转载请注明出处

#include <iostream>
#include <cstdio>
#include <memory.h>
#include <algorithm>
#define ABS(x) ((x) >= 0 ? (x) : (-(x)))
using namespace std;
const int inf = 1 << 29;
const int maxn = 60002;
const int bal = 1002;
const int maxm = 22;
struct peo
{
    int x,y;
    int a,b,id;
    bool operator < (const peo &other) const
    {
        if(a == other.a) return b > other.b;
        return a < other.a;
    }
}can[maxn];
bool vis[maxm][bal << 1],record[bal << 1];
int dp[maxm][bal << 1],path[maxm][bal << 1],ans[maxm];
int m,n,top,tot;

void read()
{
    for(int i=1;i<=n;i++)
    {
        scanf("%d %d",&can[i].x,&can[i].y);
        can[i].a = can[i].x - can[i].y;
        can[i].b = can[i].x + can[i].y;
        can[i].id = i;
    }
    sort(can + 1 , can + n + 1);
    return;
}

void make()
{
    top = 1;
    int pre = -100,cnt = 0;
    for(int i=1;i<=n;i++)
    {
        if(can[i].a != pre)
        {
            pre = can[i].a;
            cnt = 1;
            can[top++] = can[i];
        }
        else
        {
            cnt++;
            if(cnt <= m) can[top++] = can[i];
        }
    }
    return;
}

void check(int i,int j)
{
    while(path[i][j] != -1)
    {
        int cur = path[i][j];
        record[cur] = true;
        i--;
        j -= can[cur].a;
    }
    return;
}

void solve()
{
    memset(vis,false,sizeof(vis));
    memset(dp,0,sizeof(dp));
    memset(path,-1,sizeof(path));
    vis[0][bal] = true;
    for(int i=0;i<m;i++)
    {
        for(int j=0;j<bal*2;j++)
        {
            if(vis[i][j] == false) continue;
            memset(record,false,sizeof(record));
            check(i,j);
            for(int k=1;k<top;k++)
            {
                if(record[k] == false)
                {
                    vis[i+1][j+can[k].a] = true;
                    if(dp[i+1][j+can[k].a] < dp[i][j] + can[k].b)
                    {
                        dp[i+1][j+can[k].a] = dp[i][j] + can[k].b;
                        path[i+1][j+can[k].a] = k;
                    }
                }
            }
        }
    }
    int bj;
    for(int i=0;;i++)
    {
        if(i == 0 && vis[m][bal])
        {
            bj = bal;
            break;
        }
        else if(i && vis[m][bal - i] && vis[m][bal + i])
        {
            if(dp[m][bal - i] > dp[m][bal + i])
            {
                bj = bal - i;
            }
            else
            {
                bj = bal + i;
            }
            break;
        }
        else if(vis[m][bal - i])
        {
            bj = bal - i;
            break;
        }
        else if(vis[m][bal + i])
        {
            bj = bal + i;
            break;
        }
    }
    tot = 0;
    int A = 0, B = 0;
    while(path[m][bj] != -1)
    {
        ans[tot++] = can[path[m][bj]].id;
        A += can[path[m][bj]].x;
        B += can[path[m][bj]].y;
        bj -= can[path[m][bj]].a;
        m--;
    }
    sort(ans , ans + tot);
    printf("%d %d\n",A,B);
    for(int i=0;i<tot;i++)
    {
        if(i) printf(" ");
        printf("%d",ans[i]);
    }
    puts("");
    return;
}

int main()
{
    while(~scanf("%d %d",&n,&m))
    {
        read();
        make();
        solve();
    }
    return 0;
}

抱歉!评论已关闭.