[NOIP模拟题]最佳旅行

13 篇文章 0 订阅
6 篇文章 0 订阅

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

Input
第一行一个数N
接下来一个 NN 的矩阵,其中元素 Fi,j 代表导游 i 对景点j的熟悉度。
接下来一个 NN 的矩阵,其中元素 Li,j 代表导游 i 对景点j的喜爱度。
N<=17 1<=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;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值