hdu 4049 - Tourism Planning

题目:一些朋友旅游,他们的路线及起点终点都已经确定。每个人都可以中途离开队伍,或者干脆就不去,

            一旦离开就不可以再回来;每座城市都有一个消费值cost;每个人对每座城市有一个兴趣值inter;

            只要两个人呆在一起,他们就可以获得一个共享福利bonus;现在要求可能获得的总最大值;

            若总最大值为负,则输出 STAY HOME。

分析:dp,状态压缩。

            阶段:以景点的参观顺序为阶段;

            状态:参观到每个景点时 N 个人会有2^N 种状态(每个人去不去);

            决策:当前景点如果 某个人在参观则前面的景点必然参观,否则有两种可能(上个景点参观否);

                      取得其中的最大值 + 这个景点本状态能获得的价值;

            处理:2^10 = 1024 用位运算处理方便一些,决策过程中可利用heap或者bfs求出所有的之前状态。

说明:(2011-09-18 23:59)。

#include <iostream>
#include <cstdlib>
#include <cstring>

using namespace std;

int Maps[ 11 ][ 11 ];
int Cost[ 11 ];
int Inst[ 11 ][ 11 ];
int F[ 11 ][ 1025 ];
int Stat[ 11 ];
int Q[ 11 ][ 1025 ];

int main()
{
    int N,M;
    while ( cin >> N >> M && N ) {
        for ( int i = 1 ; i <= M ; ++ i )
            cin >> Cost[ i ];
        for ( int i = 1 ; i <= N ; ++ i )
        for ( int j = 1 ; j <= M ; ++ j )
            cin >> Inst[ i ][ j ];
        for ( int i = 1 ; i <= N ; ++ i )
        for ( int j = 1 ; j <= N ; ++ j )
            cin >> Maps[ i ][ j ];
        
        int V = (1<<N)-1;
        for ( int i = 0 ; i <= N ; ++ i )
        for ( int j = 0 ; j <= V ; ++ j )
            F[ i ][ j ] = -10000001;
        
        for ( int j = 0 ; j <= V ; ++ j )
            F[ 0 ][ j ] = 0;
        
        for ( int i = 1 ; i <= M ; ++ i ) 
        for ( int j = 0 ; j <= V ; ++ j ) {
            //将位状态存入数组 
            int temp = j;
            for ( int k = 1 ; k <= N ; ++ k ) {
                Stat[ k ] = temp%2;
                temp /= 2;
            }
            
            //求出这个状态能得到的价值 
            int Save = 0;
            for ( int k = 1 ; k <= N ; ++ k )
                if ( Stat[ k ] )
                    Save += Inst[ k ][ i ] - Cost[ i ];
            for ( int p = 1 ; p <= N ; ++ p )
            for ( int q = p+1 ; q <= N ; ++ q )
                if ( Stat[ p ] && Stat[ q ] )
                    Save += Maps[ p ][ q ];
            
            //求出所有的之前状态 
            int count = 0;
            Q[ 0 ][ 0 ] = j;
            for ( int k = 1 ; k <= N ; ++ k )
                if ( !Stat[ k ] ) {
                    for ( int p = 0 ; p < (1<<count) ; ++ p ) {
                        int New = Q[ count ][ p ];
                        Q[ count+1 ][ p*2+0 ] = New;
                        Q[ count+1 ][ p*2+1 ] = New|(1<<(k-1));
                    }
                    ++ count;
                }
            
            //取得之前状态的最大值 
            int Min = -10000001;
            for ( int k = 0 ; k < (1<<count) ; ++ k ) {
            //    cout << Q[ count ][ k ] << " ";
                if ( Min < F[ i-1 ][ Q[ count ][ k ] ] )
                    Min = F[ i-1 ][ Q[ count ][ k ] ];
            }
            F[ i ][ j ] = Min+Save;
        //    cout << "V = " << F[ i ][ j ] << endl;
        }
        
        int Max = -10000001;
        for ( int i = 1 ; i <= M ; ++ i ) 
        for ( int j = 0 ; j <= V ; ++ j )
            if ( Max < F[ i ][ j ] )
                Max = F[ i ][ j ];
        
        if ( Max > 0 )
            cout << Max << endl;
        else
            cout << "STAY HOME" << endl;
    }
    return 0;
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值