2011 Asia Beijing Regional Online Contest-1010 hdu4049 Tourism Planning

这是一道状态压缩DP题目

用dp[i][1024] 可以记下经过第i个城市的所有状态

在状态转移的时候,dp[i-1][j]中的j必须在 dp[i][k] 的k为1的对应位上也为1

例如,如果k为10110,那么j可以使10110或10111或11110或11111或10110,我们可以提前处理出所有能转移到k的状态

转移过程就非常简单了

做这道题的时候再位运算的处理上wrong answer 了好几次,最后竟然是错在位运算运算符的优先级上~~


#include <iostream>
#include <cstdio>
#include <algorithm>
#include <memory.h>
#include <vector>

using namespace std;

const int N = 1025;
const int M = 15;
const int INF = 1 << 30;

int g_cost[M];
int g_n,g_m;
struct fiend
{
    int interest[M];
    int value[M];
    void getvalue()
    {
        for(int i = 1;i <= g_m;i++)
            value[i] = interest[i] - g_cost[i];
    }
}g_f[M];

vector<int> g_havepeo[N],g_before[N];
int g_relation[M][M];
int dp[M][N];
int g_len,g_ship[N];
void INIT();
void sol();
int getfriendship(int i);
int increase(int j,int gap);

int main()
{
    INIT();
    while(scanf("%d%d",&g_n,&g_m)!=EOF &&(g_n || g_m))
    {
        for(int i = 1;i <= g_m;i++)
            scanf("%d",&g_cost[i]);
        for(int i = 1;i <= g_n;i++)
        {
            for(int j = 1;j <= g_m;j++)
                scanf("%d",&g_f[i].interest[j]);
        }
        for(int i = 1;i <= g_n;i++)
            for(int j = 1;j <= g_n;j++)
                scanf("%d",&g_relation[i][j]);
        for(int i = 1;i <= g_n;i++)g_f[i].getvalue();
        g_len = 1 << g_n;
        sol();
    }
}

void INIT()
{
    int x[11];
    x[1] = 1;
    for(int i = 2;i < 11;i++)x[i] = x[i-1] << 1;
    for(int i = 0;i < 1024;i++)
    {
        g_havepeo[i].clear();
        for(int j = 1;j < 11;j++)
            if(i & x[j])
                g_havepeo[i].push_back(j);
    }
    for(int i = 0;i < 1024;i++)
    {
        g_before[i].clear();
        for(int j = i;j < 1024;j++)
        {
            if((j&i) == i)
            {
                g_before[i].push_back(j);
            }
        }
    }
    memset(dp,0,sizeof(dp));
}

void sol()
{
    for(int i = 1;i < g_len;i++)
    {
        g_ship[i] = getfriendship(i);
    }
    for(int gap = 1;gap <= g_m;gap++)
    {
        for(int j = 0;j < g_len;j++)
        {
            int tmp = increase(j,gap) + g_ship[j];
            int max = -INF;
            for(int k = 0;k < g_before[j].size()&&g_before[j][k] < g_len;k++)
            {
                if(tmp + dp[gap-1][g_before[j][k]] > max)
                    max = tmp + dp[gap-1][g_before[j][k]];
            }
            dp[gap][j] = max;
        }
    }
    int max = -INF;
    for(int i = 0;i <= g_len;i++)
    {
        if(dp[g_m][i] > max)
            max = dp[g_m][i];
    }
    if(max <= 0) printf("STAY HOME\n");
    else if(max > 0) printf("%d\n",max);
}

int getfriendship(int i)
{
    int tmp = 0;
    for(int j = 0;j < g_havepeo[i].size();j++)
    {
        for(int k = j;k < g_havepeo[i].size();k++)
        {
            tmp += g_relation[g_havepeo[i][j]][g_havepeo[i][k]];
        }
    }
    return tmp;
}

int increase(int j,int gap)
{
    int tmp = 0;
    for(int i = 0;i < g_havepeo[j].size();i++)
    {
        tmp += g_f[g_havepeo[j][i]].value[gap];
    }
    return tmp;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值