首先,说以下本题目的状态转移方程为:
以d[ i ][ j ] = max ( d[ k ][ j +1 ] + sumc(i+1-->k , j+1) 其中sumc(i+1-->k , j+1)代表从i+1到k都到j+1避难 ) ;
首先说明为什么一定是连续 11...22..33...44..5..6 连续的取值;
所有 的 n支队伍和m个避难所要先排序;
我们可以假设最优解中除了必须的从n中取出的m个依次 对应 1 ,2, 3, 4,5,6,7直到m则这m只队伍一定是升序的,可贪心证明;
然后剩下的n-m支队伍会和在一起构成11...22..33...44..55..66..因为16...22..33...44..55..16. 任意两个位置错位则交换过来的解不会更差;
#include<cstdio>
#include<vector>
#include<queue>
#include<cmath>
#include<cstring>
#include <cstdlib>
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long LL;
const LL inf = 1e14;
const int maxn = 4010;
struct node{
long long x,p,res;
node(int x=0,int p=0):x(x),p(p){}
bool operator < (const node& rhs)const{
return x<rhs.x;
}
};
LL d[maxn][maxn],n,m,res[maxn];
node a[maxn],b[maxn];
bool vis[maxn][maxn];
LL dp(int i,int j){
if(vis[i][j]) return d[i][j];
vis[i][j] = true;
if(i==n){
if(j<m) return d[i][j]=inf;
return d[i][j] = 0;
}
d[i][j] = inf;
if(j<m)
d[i][j]=dp(i+1,j+1)+abs(a[i+1].x-b[j+1].x);
if(n-(i+1)>=m-j)
d[i][j]=min(d[i][j],dp(i+1,j)+abs(a[i+1].x-b[j].x));
return d[i][j];
}
void print_ans(int i,int j){
if(i==n) return ;
if(d[i][j]==dp(i+1,j+1)+abs(a[i+1].x-b[j+1].x)){
res[a[i+1].p] = b[j+1].p;
print_ans(i+1,j+1);
}
else {
res[a[i+1].p] = b[j].p;
print_ans(i+1,j);
}
}
int main()
{
while(scanf("%lld",&n)==1){
for(int i=1;i<=n;i++){
scanf("%lld",&a[i].x);
a[i].p=i;
}
scanf("%lld",&m);
for(int i=1;i<=m;i++){
scanf("%lld",&b[i].x);
b[i].p = i;
}
sort(a+1,a+n+1);
sort(b+1,b+m+1);
for(int i=0;i<=n;i++)
for(int j=0;j<=m;j++)
vis[i][j] =false;
printf("%lld\n",dp(1,1)+abs(a[1].x-b[1].x));
res[a[1].p]=b[1].p;
print_ans(1,1);
for(int i=1;i<=n;i++){
if(i>1) printf(" ");
printf("%d",res[i]);
}
printf("\n");
}
return 0;
}