最もn列で見つけることができる便利な、そしてDP-ような圧力だけで結構です。
#include <ビット/ STDC ++ H> 使用して 名前空間STDを、 const int型 INF = 0x3f3f3f3f 。 INTの N、M、[ 12 ] [ 2007 ]、B [ 12 ] [ 12 ]。 INT和[ 12 ] [ 1 << 12 ]。 INT DP [ 2 ] [ 1 << 12 ]。 INT * F = DP [ 0 ]。 INT * G = DP [ 1 ]。 int型の MX [ 2007 ]、ID [ 2007 ]; 列をなしてINT getNextを(int型マスク){ int型 lastbit =マスク&1 。 マスク >> = 1 。 マスク | = lastbit <<(N - 1 )。 戻り値のマスク。 } int型のmain(){ int型の T。scanf関数(" %のD "、&T)。 一方、(T-- ){ scanf関数(" %d個の%のD "、&N、&M)。 以下のために(int型 i = 0 ; iがmを<; iは++)MXを[I] = 0 ; 以下のために(int型 i = 0 ; iがN <I ++は{) のための(INT J = 0 ; J <Mであり、j ++ ){ scanf関数(" %のD "、および[I] [J])。 MX [J] = MAX(MX [J]、[I] [J])。 } } のために(int型 i = 0 ; iがmを<; I ++の)IDを[I] = I。 ソート(ID、ID + M [b](int型のx、int型のY){ 戻り MX [X]> MX [Y]; }); 用(INT O = 0 ; 0 <N&O <M、O ++ ){ int型のx = ID [O]。 用(int型 J = 0 ; nはJ <; J ++)B [O] [j]は= [j]を[X]。 } のために(int型 i = 0 ; iは分(N、M)<; iは++の){ ための(int型マスク= 0 ;マスク<(1 << n)は、マスク++ ){ 和[I] [マスク] = 0 ; 以下のための(int型 J = 0; J <N; J ++ ){ 場合(マスク>> J&1 ){ 和[I] [マスク] + = B [i]は[J]。 } } } } のために(int型 i = 0 ; iは<(1個の << N)、iは++)F [I] = 0 ; 以下のために(int型 i = 0 ; iは++; iは分(N、M)< ){ スワップ(F、G)を、 用(int型マスク= 0 ;マスク<(1 << n)は、マスク++){ F [マスク] = G [マスク]。 用(INTキス=(平手キス平手キス=マスク;;平手- 1)&マスク){ [マスク] F = MAX([マスク] G [平手キス] +和[I] [マスク^ F 平手キス])。 もし(キス==平手0)休憩を。 } } の場合(INT S = 0 ; <(マスク1 << n)は、マスク++ ){ int型 CUR = マスク。 以下のための(int型 I = 1; 私は、n <; 私は++ ){ CUR = getNextを(CUR)。 F [CUR] = MAX([CUR]、F [マスクF)。 } } } のprintf(" %Dを\ n "、F [(1 << N) - 1 ])。 } 戻り 0 。 } / * * /