模拟赛-12 connect
作者:互联网
题意
工厂里有 \(N\) 个机器,每个机器与其他若干个机器之间需要连线,现在要将这 \(N\) 个机器安放在 \(1\)~\(N\) 这 \(N\) 个位置上,两个处在 \(D_i\) 和 \(D_j\) 位置的机器连线费用为 \(|D_i-D_j|\),求最小的连线费用。
\(1\le N\le 20\)
输入
第一行两个整数 \(N,M\) 表示机器的数量和需要连线的关系数
接下来 \(M\) 行,每行 \(2\) 个数字 \(x,y\) 表示机器 \(x\) 和机器 \(y\) 之间需要连线
输出
一行一个整数表示最小花费
Solution
解法1:玄学
没想出来怎么状压只好退了个火
没想到竟然碾标算/jk
最开始就初始化一个位置数组 \(p\),\(p[i]\) 表示第 \(i\) 台机器的位置
然后每次随机交换两个位置, \(N^2\) 统计新的花费,以 \(exp(-diff/T)\) 的概率接受坏解(以后可能变优)
然后大概 \(30\) 次退火就A了/fad
用时500+ms,std用时1600+ms
解法2:正解状压
首先对于状压的一个状态 \(i\) 要理解到底是啥意思
设二进制表示下的 \(i\) 有 \(x\) 个 \(1\),那么这个状态表示这 \(x\) 个 \(1\) 的位置的机器安放在了 \(1\)~\(x\) 位置
所以我们枚举一台未安放的机器把他放在第 \(x+1\) 位
假设当前状态为 \(i\) 我们枚举机器 \(j\) 放在第 \(x+1\) 位(\((i\&(1<<j))==0\))
但是这个代价就不能 \(O(N)\) 再去算一次了,不然就成了 \(O(N^2 2^N)\) 当场写假掉
我们可以计算对于每一个状态 \(i\) 有多少对冲突的关系(边的端点分别在已选中集合和未选中集合的边数),在安排机器的时候累加即可
正确性:假如第 \(i\) 次加入选中集合的机器需要和第 \(j\) 次加入选中集合的机器连边,为了方便描述我们设 \(i<j\)
那么在 \(i\) 加入选中集合之前边 \((i,j)\) 是不会累加的(因为这条边两端都在未选中集合),在 \(i\) 加入集合之后开始累加,累加到 \(j\) 加入集合为止,\(j\) 加入集合之后这条边的两端又在同一个集合中,不再累加,总共累加 \(j-i\) 次,刚好就是这个关系的花费
这个关系怎么求嘛....
首先我们先计算一个东西,状态 \(i\) 的二进制表示下 \(1\) 的个数,设为 \(sz[i]\) 递推即可: \(sz[i]=sz[i>>1]+(i\&1)\)
然后对于每一台机器 \(u\),在输入的时候就处理出一个数组 \(a[u]\) 表示需要和点 \(u\) 连接的若干台机器的二进制表示
设状态 \(i\) 的冲突关系数为 \(s[i]\) 那么有 \(sum[i]=\sum\limits_{j=0}^{N}sz[i\&a[j]]\) \(((1<<j)\& i==0)\)
(找出一个没选的数字,然后把既和他要连边也已经选取的数字累加进去)
状态转移方程: \(F[i|(1<<j)]=F[i]+s[i]\)
鸽完了/cy
标签:sz,12,机器,连线,累加,选中,connect,集合,模拟 来源: https://www.cnblogs.com/ShadderLeave/p/13194089.html