ZOJ_3620 Escape Time II

http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=3620

题意:

有N个房间,每个房间都有一定的珠宝量,给你T秒钟,从起点s出发,问如果要求在t之前

要达到终点e你最多能拿多少珠宝。

思路:

本题的N<=10,可以直接枚举每种状态,然后进行一次dp就可以了。

#include<stdio.h>
#include<string.h>
#include<vector>
#include<algorithm>
const int inf = 0x3fffffff ;
int n , m , t ;
int s, e , S;
int val[15] ;
int map[13][13] ;
int dp[13][1<<10] ;

std::vector< std::pair<int,int> > v ;
bool comp( std::pair<int , int > p1,  std::pair<int , int>p2 ){
    return p1.first > p2.first ;
}
bool solve(){
    for(int k=0;k<n;k++){
        for(int i=0;i<n;i++){
            for(int j=0;j<n;j++){
                if( map[i][k]!=inf && map[k][j]!=inf && map[i][j] > map[i][k] + map[k][j] )
                    map[i][j] = map[i][k] + map[k][j] ;
            }
        }
    }
    if( map[s][e] == inf )  return false ;
    std::sort(v.begin() , v.end() , comp ) ;
    return true ;
}

bool is_ok(int b){
    if( (b&(1<<s))!=0 && (b&(1<<e))!=0 )    return true ;
        return false ;
}
bool is_single(int a){
    int b = a & (a - 1 ) ;
    if(b == 0)  return 1 ;
    else        return 0;
}

int DP(int i , int j){
    if( dp[i][j]!=-1 )  return dp[i][j];
    if( is_single(j) ){
        if( i == s )
            dp[i][j] = 0 ;
        else    dp[i][j] = inf ;
        return dp[i][j] ;
    }
    int jj = j ^ (1<<i) ;
    int _min = inf ;
    for(int ii=0;ii<n;ii++){
        if( (jj&(1<<ii)) !=0 ){
            if( DP(ii , jj)!= inf  && map[ii][i]!=inf && DP(ii,jj)+map[ii][i] < _min)
                _min = DP(ii, jj) + map[ii][i] ;
        }
    }
    dp[i][j] = _min ;
    return dp[i][j] ;
}
int get_ans(int b){
    memset(dp,  -1 , sizeof(dp));
    return DP(e ,b);
}

void DP(){
    for(int i=0;i<v.size();i++){
        int a = v[i].first , b = v[i].second ;
        if( is_ok(b) ){
            if( t>=get_ans( b ) ){
                printf("%d\n",a) ;  return ;
            }
        }
    }
    printf("0\n");  return ;
}

int main(){
    int a,b ,c ;
    while( scanf("%d%d%d",&n,&m,&t) == 3){
        scanf("%d %d",&s,&e);
        for(int i=0;i<n;i++)   scanf("%d",val+i);
        S = 1 << n ;
        v.clear() ;
        for(int j=1;j<S;j++){
            int a = 0 ;
            for(int i=0;i<n;i++){
                if( (j&(1<<i)) != 0 ){
                    a += val[i] ;
                }
            }
            v.push_back( std::make_pair(a ,j) );
        }
        for(int i=0;i<n;i++){
            for(int j=0;j<n;j++)
                map[i][j] = inf ;
            map[i][i] = 0 ;
        }
        for(int i=0;i<m;i++){
            scanf("%d %d %d",&a,&b,&c) ;
            if(c < map[a][b] )  map[a][b] = map[b][a] = c ;
        }
        if( !solve() ){
            printf("0\n");  continue ;
        }
        DP() ;
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值