题意:n个施工队,m个避难所,在一个正x坐标轴上,给出每个施工队坐标和每个避难所坐标,要求每个施工队到一个避难所避难,且每个避难所至少有一个施工队,求所有施工队所走的距离和的最小值。
题解:先把施工队和避难所排个序,可以设状态dp[i][j]表示前i个施工队用j个避难所的最小花费。容易得出第i个施工队到第j个避难所造成的花费是最小的。
即dp[i][j]=min(dp[i-1][j-1],dp[i-1][j])+abs(a[i].x-b[j].x)。
#include <bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
typedef long long ll;
struct Node
{
long long x;
ll id;
ll t;
bool operator < (const Node & tt) const
{ return x < tt.x; }
}a[4005],b[4005];
bool cmp(const Node s1,const Node s2)
{
return s1.id<s2.id;
}
ll vis[4005][4005];
ll n,m;
void print(ll i,ll j)
{
if(i==1&&j==1)
{
a[i].t=b[j].id;return ;
}
print(i-1,j-1+vis[i][j]);
a[i].t=b[j].id;
}
ll dp[4005][4005];
int main()
{
while(scanf("%d",&n)!=EOF)
{
memset(vis,0,sizeof(vis));
memset(dp,0,sizeof(dp));
for(ll i=1;i<=n;i++)
{
scanf("%d",&a[i]);
a[i].id=i;
}
scanf("%d",&m);
for(ll i=1;i<=m;i++)
{
scanf("%d",&b[i]);
b[i].id=i;
}
sort(a+1,a+n+1);
sort(b+1,b+1+m);
for(ll i=1;i<=n;i++)
{
for(ll j=1;j<=m;j++)
{
if(j==1) dp[i][j]=dp[i-1][j]+abs(a[i].x-b[j].x),vis[i][j]=1;
else if(i==j) dp[i][j]=dp[i-1][j-1]+abs(a[i].x-b[j].x),vis[i][j]=0;
else
{
dp[i][j]=min(dp[i-1][j-1],dp[i-1][j])+abs(a[i].x-b[j].x);
vis[i][j]=(dp[i-1][j]>dp[i-1][j-1])?0:1;
}
}
}
printf("%lld\n",dp[n][m]);
print(n,m);
sort(a+1,a+n+1,cmp);
for(ll i=1;i<=n;i++)
printf("%d%c",a[i].t,(i==n)?'\n':' ');
}
return 0;
}