[NOIP模拟题]最佳旅行

本文介绍了一个关于旅行计划的算法问题,旨在寻找最佳的导游景点匹配方案,以最大化导游的熟悉度与喜爱度总和之积。通过使用动态规划与深度优先搜索结合剪枝的方法,有效地解决了这一问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Description
Bsny在杭州旅行,想去N个景点,于是他找来N个导游,每个导游负责带Bsny去一个景点玩一天,因此需要N个导游。这个N个导游对于N个景点有不同的熟悉度和喜爱度。为了旅游愉快,Bsny想尽量让每个导游可以去熟悉度和喜爱度最高的景点,但显然无法满足所有导游,因为Bsny希望想一种方案,使得每个导游的熟悉度总和与喜爱度总和之
积最大。你能告诉他最大能达到多少吗?

Input
第一行一个数N
接下来一个NN的矩阵,其中元素Fi,j代表导游i对景点j的熟悉度。
接下来一个NN的矩阵,其中元素Li,j代表导游i对景点j的喜爱度。
N<=171<=Fi,j,Li,j<=1,000

Output
仅一行表示最大的熟悉度总和与喜爱度总和之积。

Sample Input
3
1 2 3
2 3 1
3 1 2
1 2 3
2 3 1
3 1 2

Sample Output
81

样例解释
1导游选择3景点,2导游选择2景点,3导游选择1景点。
于是熟悉度之和为(3+3+3)=9, 喜爱度之和为(3+3+3)=9, 积为9*9=81 这个是最大方案。

HINT

思路
这道题的数据范围很小,一定是搜索。但是一般的搜索会TLE,那么要想一些优化措施了,令fi,S表示选择了i个景点的状态为S的最大熟悉度之和,gi,S表示选择了i个景点的状态为S的最大喜爱度之和,如果当前选择的熟悉度之和为sumx,喜爱度之和为sumy,最终答案为ans,那么(sumx+fi,S)(sumy+gi,S)>=ans才可能更新答案,这样剪枝所得到的时间复杂度很低了。

代码

#include <cstdio>
#include <algorithm>

const int maxn=17;

int n,f[maxn+2][1<<maxn],g[maxn+2][1<<maxn],ans;
int x[maxn+1][maxn+1],y[maxn+1][maxn+1];

int dfs(int now,int s,int sumx,int sumy)
{
    if(now>n)
    {
        ans=std::max(ans,sumx*sumy);
        return 0;
    }
    if((f[now][s]+sumx)*(g[now][s]+sumy)<ans)
    {
        return 0;
    }
    for(int i=1; i<=n; i++)
    {
        if(!(s&1<<(i-1)))
        {
            dfs(now+1,s|1<<(i-1),sumx+x[now][i],sumy+y[now][i]);
        }
    }
    return 0;
}

int main()
{
    scanf("%d",&n);
    for(int i=1; i<=n; i++)
    {
        for(int j=1; j<=n; j++)
        {
            scanf("%d",&x[i][j]);
        }
    }
    for(int i=1; i<=n; i++)
    {
        for(int j=1; j<=n; j++)
        {
            scanf("%d",&y[i][j]);
        }
    }
    for(int i=n; i>0; i--)
    {
        for(int j=0; j<1<<n; j++)
        {
            for(int k=1; k<=n; k++)
            {
                if(!(j&(1<<(k-1))))
                {
                    f[i][j]=std::max(f[i][j],f[i+1][j|(1<<(k-1))]+x[i][k]);
                    g[i][j]=std::max(g[i][j],g[i+1][j|(1<<(k-1))]+y[i][k]);
                }
            }
        }
    }
    dfs(1,0,0,0);
    printf("%d\n",ans);
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值