数据结构可以分为线性结构、半线性结构、非线性结构。最基本的线性结构是序列。序列分为向量和列表。向量的逻辑次序称为秩,列表逻辑上相邻的数据项采用间接定址的方式通过封装后的位置相互引用。
#include<iostream>
#include<algorithm>
#include<cstring>using namespace std;const int N=21;//表示点的最大的数目
const int M=1<<N;//二进制状态的数字
int n;//点的数目
int f[M][N],weight[N][N];//f 的第一维表示状态,第二维表示目前到哪个点
//状态的意思就是当前哪些点被用过了,也就是说,1 表示被用过了,0 表示没被用过
//weight 表示权重,就是我们输入的那个东西int main(){scanf("%d",&n);for(int i=0;i<n;i++){for(int j=0;j<n;j++){scanf("%d",&weight[i][j]);}}memset(f,0x3f,sizeof f);//因为是求最小值,所以初始的时候就//初始化为正无穷f[1][0]=0;//表示 0 这个点被用了,但是还没有移动,所以是 0//下面是关键for(int i=0;i<1<<n;i++){//枚举所有的状态for(int j=0;j<n;j++){//枚举每一个点if(i>>j&1){//位运算常用的,这个是看啥,看不懂,这里表示的是// j 这个点用过了,那是为啥呢for(int k=0;k<n;k++){//枚举的是另外一个点if(i>>k&1){//我感觉有点奇怪,这不是表示 k 这个点被用过了吗//哦哦,转移之后确实被用过了f[i][j]=min(f[i][j],f[i-(1<<j)][k]+weight[k][j]);}//这个位运算记住就好了,给我的感觉就是减掉一个 1}//比如说 i=1011 ,然后 j=1000 ,减掉之后就是 11 ,应该是这个意思}}}printf("%d\n",f[(1<<n)-1][n-1]);//有优先级的问题,记得要加括号//就是二进制数字全是 1 ,表示所有点都走过了,然后刚好到终点,就是答案return 0;
}
这题对我来说是真的难。想放弃了都。题解看了两三遍。硬是看不明白。现在大概懂一点点了。就是我们把第一维看作是二进制压缩的状态。然后第二维表示的是当前的点是哪个点。当前的点一定要在前面的状态里面表示为 1 1 1 。这个是啥意思呢。就是因为我们要算这个点,虽然是算完这个点才把这个点算作已经用完了。但是我们得先把这个点标记为 1 1 1 才能算这个点。我个人感觉有点像先斩后奏,或者先上车后补票的感觉。然后的话,我们枚举了两个点,从 k
这个点走到 j
这个点。需要 j
这个点没有被用过,才能转移。假设 j
这个点被用过了,再转移,就至少是第二次经过 j
这个点。不符合题意。难住我的还有位运算。因为我接触这个东西比较少。看到很陌生。然后就差不多了,结合注释也基本能理解意思了。