Phrvth量子力学对不起,爱因斯坦

传递游戏【题解】

Hi,Phrvth·2023-01-12 16:10·115 次阅读

传递游戏【题解】

Description

毛大神最近在玩一个传递游戏,即有 N 个人在做传递物品的游戏,这 N 个人的编号为 123...N1N

游戏规则是这样的:开始时物品可以在任意一人手上,他可把物品传递给其他人中的任意一位;下一个人可以传递给未接过物品的任意一人。

即物品只能经过同一个人一次,而且每次传递过程都有一个代价;不同的人传给不同的人的代价值之间没有联系;

毛大神想知道当物品经过所有 N 个人后,整个过程的最小的代价总和是多少。

Format#

Input#

第一行为 N,表示共有 N 个人;

以下为 N × N 的矩阵,第i行第 j 列的数为 A[i][j],表示物品从编号为 i 的人传递到编号为 j 的人所花费的代价,其中 A[i][i]=1(因为物品不能自己传给自己)。

Output#

输出共一行一个数,为最小的代价总和。

Samples#

输入数据 1
2
-1 9794
2724 -1
输出数据 1
2724
Limitation
对于 50% 的数据,1N11

对于 100% 的数据,1N161A[i][j]10000A[i][i]=1

浅浅的谈一下

  • 第一反应肯定是搜索,然后回溯,时间复杂度乍一看可以,我们算算

  • ……其实我也不会算(一个蒟蒻),为什么不行呢,因为有人试过了,45

  • 怎么办?

  • 一看这题目的问法, 就有一种dp的思路,配合这数据范围,配合这题目,状压dp应运而生!

  • 什么是状压dp(其实我写过了,就copy过来了)

  • “状压DP 又叫集合动态规划。是以结合信息为状态的特殊的动态规划的问题。主要有传统集合动态规划和基于连通性状态压缩的动态规划两种。” ————百度

  • 是不是感觉很高大尚?(我也觉得

  • 其实很简单(不是我说的

  • 状压dp的样子

  • 我们回到题目:我们把每个人看成每一个点,被传递过标记成一,他就变成了这样一个样子,很想二进制枚举是吧
    长这样
  • 怎么转移?#

  • (<<):左移

    • 在十进制上是乘法
    • 在二进制上是把整体往左挪一位,例如:100<<1=1000
    • (>>): 右移,和左移原理一样,把整体往右移一位
    • 对于每个状态,我们枚举这个点有没有选到:如100010这个状态没有选第三个点
  • 这就要用到左移与运算

  • 如果我想要表示一个100,表示第三个状态已被选怎么办?

  • 很容易发现100=1<<(31)

  • 于是我们可以总结:i=1<<(i1)

  • 于是我们就可以用i&1<<(j1)(i表示当前状态,j表示当前枚举到的点)来表示i状态有没有选点j

  • 考虑转移?#

  • 枚举每个状态,再枚举这个状态选了那些点,再由这些点进行转移

  • 什么意思?

  • 例如状态10001,这个状态包含1,52个点

  • 如果点2可以接到点1后面

  • 那么f[11001]=max(min)(f[10001]+v,f[11001])

  • 然后输出f[(1<<n)1]全部点被选即可

  • 这道题咋写

  • 假如枚举到一个状态T,枚举这个状态有多少个存在的点,再由这个点去转移到另外没有被选过的点

  • 等等,怎么判断T中,球传到哪里了?

  • 于是,我们就要开二维数组dpiTiT

  • 于是就有我们的满分代码了(注意<<的优先级!)

Code

Copy
#include<bits/stdc++.h> //值得写解题报告! using namespace std; int dp[20][1<<20],n,g[20][20]; //dp[i][T]到了第i个人,状态为T int main(){ cin>>n; for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) cin>>g[i][j]; memset(dp,0x3f,sizeof(dp)); for(int i=1;i<=n;i++)dp[i][1<<(i-1)]=0;//初始 for(int t=1;t<1<<n;t++)//枚举状态 for(int i=1;i<=n;i++) if(t&(1<<i-1))//在这里面 for(int j=1;j<=n;j++) if(i!=j&&!(t&(1<<j-1)))//不在这里面 dp[j][t|(1<<j-1)]=min(dp[j][t|(1<<j-1)],dp[i][t]+g[i][j]); int ans=1e9; for(int i=1;i<=n;i++) ans=min(ans,dp[i][(1<<n)-1]); cout<<ans<<endl; return 0;//注意"<<"优先级比"-"小 }

题外话:普及组的题竟然会考状压,没想到

posted @   Phrvth  阅读(115)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 使用C#创建一个MCP客户端
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示
目录
?