题意:有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;
}