当前位置:编程学习 > C/C++ >>

HDU 4284 Travel(12年天津 状态DP)

题目:给出一些城市,从1出发,旅游一圈回到1,由于花费可能不够,所以选择一些城市打工,打工之前需要花费d买一个证,工资为c。选中的城市必须去工作一次,而且只能工作一次,问能不能完成旅行

 


比赛的时候,卡了很久,当时队友用SPFA+状态DP+堆栈写的,主要是把一点考虑错了

当时把C和D合并了,其实是不对的,因为首先是要购买证,然后才能工作,否则拿不到工资。

也就是先要判断够不够买证的钱D,然后才能拿到工资。

跪舔,先用Floyd预处理最短路n^3,然后状态DP,h*h*2^h,4S+,效率很低的做法

可以用队列,堆栈加速


[cpp]
#include<iostream>  
#include<cstdio>  
#include<map>  
#include<cstring>  
#define inf 1<<28  
#define N 105  
#define Min(a,b) ((a)<(b)?(a):(b))  
#define Max(a,b) ((a)>(b)?(a):(b))  
using namespace std; 
int n,m,money,h; 
int path[N][N]; 
int dp[20][1<<16]; 
int work[20],c[20],d[20]; 
int main(){ 
    int t; 
    scanf("%d",&t); 
    while(t--){ 
        scanf("%d%d%d",&n,&m,&money); 
        for(int i=0;i<n;i++){ 
            for(int j=0;j<n;j++) 
                path[i][j]=inf; 
            path[i][i]=0; 
        } 
        for(int i=0;i<m;i++){ 
            int u,v,w; 
            scanf("%d%d%d",&u,&v,&w); 
            u--;v--; 
            path[u][v]=Min(path[u][v],w); 
            path[v][u]=path[u][v]; 
        } 
        //Floyd预处理  
        for(int k=0;k<n;k++) 
            for(int i=0;i<n;i++) 
                for(int j=0;j<n;j++) 
                    if(i!=k&&i!=j&&j!=k) 
                        path[i][j]=Min(path[i][k]+path[k][j],path[i][j]); 
        scanf("%d",&h); 
        int pos=-1; 
        for(int i=0;i<h;i++){ 
            scanf("%d%d%d",&work[i],&c[i],&d[i]); 
            work[i]--; 
            if(work[i]==0) pos=i;   //说明必需点中包含了起点1  
        } 
        //如果不包含,我们加入冗余点,便于后面处理,c和d都为0  
        if(pos==-1){ 
            work[h]=0;c[h]=0;d[h]=0; 
            pos=h++; 
        } 
        memset(dp,-1,sizeof(dp)); 
        if(money-d[pos]>=0) dp[pos][1<<pos]=money-d[pos]+c[pos];dp[pos][0]=money; 
        for(int i=0;i<(1<<h);i++){ 
            for(int j=0;j<h;j++){ 
                if(dp[j][i]==-1) continue; 
                for(int k=0;k<h;k++){ 
                    if(k==j||((1<<k)&i)) continue; 
                    //钱够在两个城市之间移动,而且够买证  
                    if(dp[j][i]>=path[work[j]][work[k]]+d[k]) 
                        dp[k][i|(1<<k)]=Max(dp[k][i|(1<<k)],dp[j][i]-path[work[j]][work[k]]-d[k]+c[k]); 
                } 
            } 
        } 
        bool ans=false; 
        for(int i=0;i<h;i++) 
            //最后判断能不能返回起点  
            if(dp[i][(1<<h)-1]>=path[work[i]][0]){ 
                ans=true; 
                break; 
            } 
        puts(ans?"YES":"NO"); 
    } 
    return 0; 

补充:软件开发 , C++ ,
CopyRight © 2022 站长资源库 编程知识问答 zzzyk.com All Rights Reserved
部分文章来自网络,