WC模拟(1.4) T1 序列

序列

题目背景:

1.4 WC模拟T1

分析:迭代加深搜索

 

当时看到这个题的时候,手推了一个错误的贪心,然后死的很惨很惨,考场上最后十来分钟才反应过来有锅,就匆匆的又写了一个贪心,然后两个取了个min······然而最后的分数还不及大搜索。

讲讲标算,显然,每一次先把xn放到x1,然后把1 ~ n翻转,可以得到一个2 * n - 2的方案,那么我们可以利用这个上界进行搜索,然后最优化剪枝,貌似这样就有32分了,然后我们发现,每一次翻转,只会改变整个序列中的一个相邻数对,那么也就是说,对于一个相邻数对,如果两个元素之差的绝对值是大于1的,那么一定需要至少一次操作才能满足条件,那么我们发现既然有上界,那么我们可以选择迭代加深,并且可以用需要修改的相邻数对的个数作为估价来进一步剪枝,总之复杂度O(能过)

 

Source:

 

/*
	created by scarlyw
*/
#include <cstdio>
#include <string>
#include <algorithm>
#include <cstring>
#include <iostream>
#include <cmath>
#include <cctype>
#include <vector>
#include <set>
#include <queue>
#include <ctime>
#include <bitset>

inline char read() {
	static const int IN_LEN = 1024 * 1024;
	static char buf[IN_LEN], *s, *t;
	if (s == t) {
		t = (s = buf) + fread(buf, 1, IN_LEN, stdin);
		if (s == t) return -1;
	}
	return *s++;
}

///*
template<class T>
inline void R(T &x) {
	static char c;
	static bool iosig;
	for (c = read(), iosig = false; !isdigit(c); c = read()) {
		if (c == -1) return ;
		if (c == '-') iosig = true;	
	}
	for (x = 0; isdigit(c); c = read()) 
		x = ((x << 2) + x << 1) + (c ^ '0');
	if (iosig) x = -x;
}
//*/

const int OUT_LEN = 1024 * 1024;
char obuf[OUT_LEN], *oh = obuf;
inline void write_char(char c) {
	if (oh == obuf + OUT_LEN) fwrite(obuf, 1, OUT_LEN, stdout), oh = obuf;
	*oh++ = c;
}

template<class T>
inline void W(T x) {
	static int buf[30], cnt;
	if (x == 0) write_char('0');
	else {
		if (x < 0) write_char('-'), x = -x;
		for (cnt = 0; x; x /= 10) buf[++cnt] = x % 10 + 48;
		while (cnt) write_char(buf[cnt--]);
	}
}

inline void flush() {
	fwrite(obuf, 1, oh - obuf, stdout);
}

/*
template<class T>
inline void R(T &x) {
	static char c;
	static bool iosig;
	for (c = getchar(), iosig = false; !isdigit(c); c = getchar())
		if (c == '-') iosig = true;	
	for (x = 0; isdigit(c); c = getchar()) 
		x = ((x << 2) + x << 1) + (c ^ '0');
	if (iosig) x = -x;
}
//*/

const int MAXN = 25;

int n, t, ans, step;
int a[MAXN], b[MAXN];

inline int check() {
	int ret = 0;
	for (int i = 2; i <= n; ++i) if (abs(a[i] - a[i - 1]) > 1) ret++;
	return ret;
}

inline bool dfs(int last, int cnt) {
	if (cnt == step) {
		bool flag = true ;
		for (int i = 1; i <= n; ++i) if (a[i] != i) flag = false;
		return flag;
	}
	if (check() + cnt > step) return false ;
	for (int i = 2; i <= n; ++i) {
		if (i != last) {
			for (int j = 1; j <= i / 2; ++j)
				std::swap(a[j], a[i + 1 - j]);
			if (dfs(i, cnt + 1)) return true ;
			for (int j = 1; j <= i / 2; ++j)
				std::swap(a[j], a[i + 1 - j]);
		}
	}
	return false ;
}

inline void solve() {
	R(n);
	for (int i = 1; i <= n; ++i) R(a[i]);
	for (step = 0; step <= 2 * n - 2; ++step) {
		if (dfs(0, 0)) {
			ans = step;
			break ;
		}
	}
	W(ans), write_char('\n');	
}

int main() {
	freopen("sequence.in", "r", stdin);
	freopen("sequence.out", "w", stdout);
	R(t);
	while (t--) solve();
	flush();
	return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值