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