TCO12 1C 1000pt : FoxAndPhotography

問題概要

長さN(<=16)の数列a,bがある。a,b内でそれぞれ隣接する項をスワップすることを繰り返してa[i]

解法

まだよく理解していないのだけど、動かすのは片方の列だけだと考えて大丈夫らしい。
それを踏まえると、(前の列の何番目までは対応付けた、既に動かした後列の集合)を状態としてdpで計算できる。

acceptされたコード

計算量O(N^2*2^N)。

#include <cstring>
#include <vector>
using namespace std;

const int MAX_N = 16;
const int INF = 1<<29;

int N;
int hs[MAX_N], bs[MAX_N];
int memo[MAX_N][1<<MAX_N];
bool visited[MAX_N][1<<MAX_N];

struct FoxAndPhotography {

	int getMinimumSwaps(vector<int> hs_, vector<int> bs_) {
		N = hs_.size();
		for(int i=0; i<N; ++i){
			hs[i] = hs_[i];
			bs[i] = bs_[i];
		}
		int ans = rec(0, 0);
		return ans == INF ? -1 : ans;
	}

	int rec(int p, int bit){
		if(p == N){
			return 0;
		}
		if(visited[p][bit]){
			return memo[p][bit];
		}
		visited[p][bit] = true;

		int& ans = memo[p][bit] = INF;
		for(int i=0, t=0; i<N; ++i)if(!((bit>>i)&1)){
			if(hs[p] < bs[i]){
				ans = min(ans, t + rec(p+1, bit | (1<<i)));
			}
			++t;
		}

		return ans;
	}

};