洛谷P2672 售货员题解 (记忆化搜索,状压DP)

一道很有意思的题目

阿明是一名推销员,他奉命到螺丝街推销他们公司的产品。螺丝街是一条死胡同,出口与入 口是同一个,街道的一侧是围墙,另一侧是住户。螺丝街一共有N家住户,第i家住户到入口 的距离为Si米。由于同一栋房子里可以有多家住户,所以可能有多家住户与入口的距离相等。 阿明会从入口进入,依次向螺丝街的X家住户推销产品,然后再原路走出去。 阿明每走1米就会积累1点疲劳值,向第i家住户推销产品会积累Ai点疲劳值。阿明是工作狂, 他想知道,对于不同的X,在不走多余的路的前提下,他最多可以积累多少点疲劳值。
【输入格式】 输入文件名为salesman.in。 第一行有一个正整数N,表示螺丝街住户的数量。 接下来的一行有N个正整数,其中第i个整数Si表示第i家住户到入口的距离。数据保证 S1≤S2≤…≤Sn<108。 接下来的一行有N个正整数,其中第i个整数Ai表示向第i户住户推销产品会积累的疲劳值。 数据保证Ai<103。
【输出格式】 输出文件名为salesman.out。 输出 N 行,每行一个正整数,第 i 行整数表示当 X=i 时,阿明最多积累的疲劳值。

记忆化搜索加上状压DP。
上代码吧。。

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
using namespace std;
int f[15][1<<15];
int r[(1<<15)+1];
int w[15][15];
int inf=(1e9)+7;
int min(int x,int y)
{
    if(x<=y) return x;
    else return y;
}
int dfs(int u,int state)
{
    //printf("%d %d\n",u,state);
    if(f[u][state]!=-1) return f[u][state];
    int rstate=state&(~(1<<u)); // vis[u] = true;
    if(rstate==0) return f[u][state]=w[u][0];
    int ans=inf;
    while(rstate) 
    {
        int p=(rstate)&(-rstate);
        int v=r[p];
        ans=min(ans,dfs(v,state&(~(1<<u)))+w[u][v]); 
        rstate-=p;
    }
    return f[u][state]=ans;
}
int main() 
{
    freopen("salesman.in","r",stdin);
    freopen("salesman.out","w",stdout);
    int n;
    scanf("%d",&n);
    for (int i=0;i<=n;i++)
    for (int j=0;j<n;j++) 
    scanf("%d",&w[i][j]);
    for (int i=0;i<= 15;i++)
    r[1<<i]=i;
    memset(f,-1,sizeof(f));
    int lim=(1<<n)-1;
    printf("%d\n",dfs(0,lim));
    return 0;
}

还算易懂的代码

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值