题意:一个三角形水域,每条边上住着n,m,k户人,他们要互相连通就得架桥,桥必须满足两个条件:1、互相不交叉。2、每一户人家都必须有至少一座桥。桥的代价为两户人家海拔高度之差,求此情况下的最优架桥方案代价。
题解:类似于一道经典DP,忘了是哪个了,可以将三角区域看成三角形,分别对三个角进行dp,方案如下:
1、对于角A,它关联的两条边分住着x1,x2...xn和zk,zk-1....z1这些人家,那么dpa[i][j]代表xi户人与zj户人搭桥且所有<i的x与所有大于j的z均已成功搭建好桥的最小代价,B,C角类似处理。
2、枚举dpa[i][j],即从A开始,最远的zj与xi之间建的桥,然后再枚举BC边上的t,从B开始,最远的yt与xi或者xi+1建桥,然后yt或yt+1与zj或zj-1建桥。取最小值。
View Code
1 #include<cstdio> 2 #include<algorithm> 3 #include<cstring> 4 using namespace std; 5 const int N=105,inf=0x1f1f1f1f; 6 int dpa[N][N],dpb[N][N],dpc[N][N],x[N],y[N],z[N]; 7 int getmin(int i,int j,int t) 8 { 9 int ans=min(dpa[i][j]+dpb[i][t]+dpc[t][j],dpa[i][j]+dpb[i][t]+dpc[t][j-1]); 10 ans=min(ans,min(dpa[i][j]+dpb[i][t]+dpc[t+1][j],dpa[i][j]+dpb[i][t]+dpc[t+1][j-1])); 11 ans=min(ans,min(dpa[i][j]+dpb[i+1][t]+dpc[t+1][j],dpa[i][j]+dpb[i+1][t]+dpc[t+1][j-1])); 12 return min(ans,min(dpa[i][j]+dpb[i+1][t]+dpc[t][j],dpa[i][j]+dpb[i+1][t]+dpc[t][j-1])); 13 } 14 int main() 15 { 16 int T,n,m,k; 17 for(scanf("%d",&T);T;T--) 18 { 19 scanf("%d%d%d",&n,&m,&k); 20 for(int i=1;i<=n;i++) 21 scanf("%d",x+i); 22 for(int i=1;i<=m;i++) 23 scanf("%d",y+i); 24 for(int i=1;i<=k;i++) 25 scanf("%d",z+i); 26 memset(dpa,0x1f,sizeof(dpa)); 27 memset(dpb,0x1f,sizeof(dpb)); 28 memset(dpc,0x1f,sizeof(dpc)); 29 dpa[0][k+1]=dpb[n+1][0]=dpc[m+1][0]=0; 30 for(int i=1;i<=n;i++) 31 for(int j=k;j>=1;j--) 32 { 33 int tp=inf,cc=0; 34 for(int t=j;t<=k;t++) 35 cc+=abs(x[i]-z[t]),tp=min(tp,cc+min(dpa[i-1][t+1],dpa[i-1][t])); 36 dpa[i][j]=tp; 37 } 38 for(int i=n;i>=1;i--) 39 for(int j=1;j<=m;j++) 40 { 41 int tp=inf,cc=0; 42 for(int t=j;t>=1;t--) 43 cc+=abs(x[i]-y[t]),tp=min(tp,cc+min(dpb[i+1][t],dpb[i+1][t-1])); 44 dpb[i][j]=tp; 45 } 46 for(int i=m;i>=1;i--) 47 for(int j=1;j<=k;j++) 48 { 49 int tp=inf,cc=0; 50 for(int t=j;t>=1;t--) 51 cc+=abs(y[i]-z[t]),tp=min(tp,cc+min(dpc[i+1][t],dpc[i+1][t-1])); 52 dpc[i][j]=tp; 53 } 54 int ans=inf; 55 for(int i=0;i<=n+1;i++) 56 for(int j=k+1;j>=0;j--) 57 for(int t=0;t<=m+1;t++) 58 ans=min(ans,getmin(i,j,t)); 59 printf("%d\n",ans); 60 } 61 return 0; 62 }