これは、圧力dpのようなものです
効果の件名:あなたの配列を与え、1〜20の間の配列番号は、スイッチング動作の回数は、業務の隣接する最小数の隣接する二つ頼んすべて同じ番号が存在しています
[I] [j]が数J I、C [i]は、フロント操作の最小数にIは、開始表すことを示しwはDPは、[S]は、状態sにおける操作の数を表します。
ヴァル[S] [i]はiが前の操作に数、状態Sを示しています。
次にDP [TMP] =分(DP [TMP]、DP [S] + valの[S] [J])
書式#include <cstdioを> する#include <CStringの> の#include <cstdlib> 書式#include <キュー> の#include < 文字列 > の#include <アルゴリズム> 書式#include <iostreamの> の#include <マップ> に#define INF 0x3f3f3f3f の#define inf64 0x3f3f3f3f3f3f3f3f 使用して 名前空間STD; const int型 MAXN = 4E5 + 10 。 typedefの長い 長いLL。 ベクトル < int型 > NUM; [DP LL 1 << 20]、C [ 21 ]。 LL W [ 21 ] [ 21 ]、ヴァル[ 1 << 20 ] [ 21 ]。 INT VIS [ 21 ]、B [ 21 ]、[MAXN]、合計[ 21 ]。 BOOL VIT [ 21 ]。 無効審判(int型x)は{ num.clear(); 以下のために(int型 I = 1 ; X; iが++ ){ 場合(X&1 )num.push_back(I)。 X >> = 1 。 } } int型メイン(){ int型 N、LEN = 0 。 scanf関数(" %のD "、&N) 以下のために(int型 i = 1 ; iが<= N; iが++ ){ scanf関数(" %dを"&[I])。 もし [++ lenが] = B(VIT [[I]]!)[i]は、 VIT [I] = 1 。 } ソート(B + 1、B + 1 + LEN)。 以下のために(int型私= 1 ; iが<= N; iが++)[I] = LOWER_BOUND(B +1、B + 1 + LEN、[I]) - B。 以下のために(int型 i = 1 ; iが<= N; iは++ ){ 和[[I]] ++ ; 用(INT J = 1 ; J <= LENあり、j ++ ){ 場合(jは[I] ==)続けます。 W [I]、[J] + = 和[J]。 } } のmemset(DP、inf64、はsizeof (DP))。 以下のために(int型 i = 1 ; iが<= N; iは++ ){ C [I]+ = I - 1 - VIS [[I]]。 VIS [[I]] ++ ; } のために(int型 i = 1 ; iがLEN = <; I ++)は、DP [ 1 <<(I - 1)] = C [I]を、 以下のために(int型私= 0 ; I <(1 << LEN); iは++ ){ ジャッジ(I)。 用(INT J = 1 ; J <= LENあり、j ++ ){ LLのXの =のC [J]。 INT TMP = 1 <<(j - 1 )。 もし |(I)==私は(TMP)は継続します。 用(int型のk = 0 ; K <num.size(); ++ K)X - = W [J] [NUM [K]。 ヴァル[I] [J] =のX。 } } のための(int型 I = 0 ; iが(< 1 ; << LEN)は、i ++は{) のために(INT J = 1 ; J <= LEN J ++ ){ int型 TMP1 = 1 - <<(J 1 ;) もし((TMP1 | I)== i)は継続します。 もし(DP [I]> = inf64)続けます。 TMP1 | = I; DP [TMP1] =分(DP [TMP1]、DP [I] + ヴァル[I] [J])。 } } のprintf(" %LLDする\ n "、DPの[(1 << LEN) - 1 ])。 リターン 0 ; }