【poj 1682】Clans on the Three Gorges 多次dp

47 篇文章 0 订阅

题意:有三条边,每条边上有点,每个点有权值,要求每一个点都至少建一条边,且边与边之间不能够交叉,花费为两点之间的权值之差,求最小权值。


什么,居然有三条边,如果考虑把三条边的每一个点都放进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;
}


评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值