题意:有三条边,每条边上有点,每个点有权值,要求每一个点都至少建一条边,且边与边之间不能够交叉,花费为两点之间的权值之差,求最小权值。
什么,居然有三条边,如果考虑把三条边的每一个点都放进dp里面作为一维的话,一一得一,三七二十一,那得有多少种情况啊?我不会三维的dp,但我会二维啊,可以先跑三次dp,预处理出从任意一条边的一个点到另外一条边的最小花费,实际上是有6种情况的,但是从a1 到 a2和a2到a1是一样的并没有什么卵区别所以就不考虑啦,最后再来枚举三条边的分割点,就好了啊。
#include<cstdio>
#include<cstring>
#include<iostream>
#include<cstdlib>
#define maxn 160
#define ll long long
#define Clear(x) memset(x,127,sizeof(x))
using namespace std;
ll n,m,p,xy[maxn][maxn],xz[maxn][maxn],yz[maxn][maxn],x[maxn],y[maxn],z[maxn];
int main(){
int cas;scanf("%lld",&cas);
while(cas--){
scanf("%lld%lld%lld",&n,&m,&p);
for(int i=0;i<=150;i++)
for(int j=0;j<=150;j++)xy[i][j]=xz[i][j]=yz[i][j]=999999;
ll ans=1e9;
for(int i=1;i<=n;i++)scanf("%lld",x+i);
for(int i=1;i<=m;i++)scanf("%lld",y+i);
for(int i=1;i<=p;i++)scanf("%lld",z+i);
xz[0][p+1]=0;
for(int i=1;i<=n;i++){
for(int j=p;j>=1;j--){
xz[i][j]=min(xz[i-1][j+1],min(xz[i-1][j],xz[i][j+1]))+abs(x[i]-z[j]);
}
}
xy[n+1][0]=0;
for(int i=n;i>=1;i--){
for(int j=1;j<=m;j++){
xy[i][j]=min(xy[i+1][j-1],min(xy[i+1][j],xy[i][j-1]))+abs(x[i]-y[j]);
}
}
yz[m+1][0]=0;
for(int i=m;i>=1;i--){
for(int j=1;j<=p;j++){
yz[i][j]=min(yz[i+1][j],min(yz[i][j-1],yz[i+1][j-1]))+abs(y[i]-z[j]);
}
}
for(int i=1;i<=n+1;i++){
for(int j=1;j<=m+1;j++){
for(int k=1;k<=p+1;k++){
ans=min(ans,xy[i][j]+yz[j][k]+xz[i][k]);
ans=min(ans,xy[i][j-1]+xz[i-1][k]+yz[j][k-1]);
ans=min(ans,xy[i][j]+xz[i][k]+yz[j][k-1]);
ans=min(ans,xz[i][k]+yz[j][k]+xy[i][j-1]);
ans=min(ans,yz[j][k]+xy[i][j]+xz[i][k+1]);
ans=min(ans,xy[i][j]+yz[j][k-1]+xz[i-1][k]);
ans=min(ans,yz[j][k]+xz[i-1][k]+xy[i][j-1]);
ans=min(ans,xz[i][k]+xy[i][j-1]+yz[j][k-1]);
}
}
}
printf("%lld\n",ans);
}
return 0;
}