这道题跟2014微软编程之美复赛的一道机器人是一模一样的题。。
首先预处理, cnt[i][j] =记录的是 在这个序列中可以取出的 不同的 <i, j> 对 ,(注意这里的i,j不是下标而是数), 而这个的意义是, 假如这个序列只存在i和j这两个数, 那么把i全部交换到j之前所花费的交换次数(毕竟每次交换i,j,就相当于少了一个<i, j> 对);
然后进行状态压缩, 0代表这种颜色已经全部都聚集在一起并且 所有已经聚集在一起的颜色 都已经移到了右边, 如(1, 1, 1, 2, 2, 3, 4, 3, 4, 3)这个就是0011这个状态,然后有两种转移方式, 一种是对于一个状态1010, 它可以由0010, 1000这两种状态转移而来, 那么枚举状态的时候就要从大往小, 另外1010也可以转移到1110,或者1011, 这时枚举状态的时候就要正向循环,而转移的时候, 要把第i位由0变成1, 那么花费就是sigema(cnt[i][x])(1 < x <n, 且第x种颜色还没有全部聚集在一起(即(s >> 1 & 1) == 0);
下面是正向转移的代码(逆向其实差别不大):
#include <set>
#include &