UVa 11212 - Editing a Book

題目:有一個數字串(1,..,n)的亂序排列,每次可以從中剪切一段連續的數字,黏貼到餘下串的任何位置;

            如:(1,2,3,4,5):剪切(2,3),餘下(1,4,5),黏貼到45中間(1,4,2,3,5);

            求把亂序串轉化成遞增序列(,..,n)的最少操作次數(剪切+黏貼,為一次操作)。

分析:圖論,搜索,IDA*。dfs搜索,使用估值函數剪枝;枚舉最小步數,找到可行解即退出。

            估值函數:a/3 + b/3,a為相鄰數字為非遞增的數對數量,最後不是n則b為1,否則b為0;

說明:開始使用dbfs,超時啦╮(╯▽╰)╭。

#include 
#include 

void copy(int n, int from[], int to[])
{
	for (int i = 0; i < n; ++ i) {
		to[i] = from[i];
	}
}

void cut_and_paste(int n, int source[], int cut_s, int cut_e, int paste_s)
{
	int cut[10], cut_count = 0;
	int left[10], left_count = 0;
	for (int i = 0; i < n; ++ i) {
		if (i < cut_s || i > cut_e) {
			left[left_count ++] = source[i];
		}else {
			cut[cut_count ++] = source[i];
		}
	}
	for (int i = 0; i < paste_s; ++ i) {
		source[i] = left[i];
	}
	for (int i = 0; i < cut_count; ++ i) {
		source[paste_s+i] = cut[i];
	}
	for (int i = paste_s; i < left_count; ++ i) {
		source[i+cut_count] = left[i];
	}
}

int valuation(int n, int paragraph[]) // 估值函數 
{
	int ans = 0;
	for (int i = 1; i < n; ++ i) {
		ans += (paragraph[i] != paragraph[i-1]+1);
	}
	return ans + (paragraph[n-1] != n);
}

int min_operation = 0, count = 0;
int dfs(int n, int d, int paragraph[])
{
	int h = valuation(n, paragraph);
	if (!h) {
		return 1;
	}
	if (3*d + h > 3*min_operation) {
		return 0;
	}
	int save[10];
	for (int s = 0; s < n; ++ s) {
		for (int e = s; e < n; ++ e) {
			for (int p = 0; p+e-s+1 < n; ++ p) {
				copy(n, paragraph, save);
				cut_and_paste(n, paragraph, s, e, p);
				if (dfs(n, d+1, paragraph)) {
					return 1;
				}
				copy(n, save, paragraph);
			}
		}
	}
	return 0;
}

int main()
{
	int n, input[10], cases = 1;
	while (~scanf("%d",&n) && n) {
		for (int i = 0; i < n; ++ i) {
			scanf("%d",&input[i]);
		}
		for (min_operation = 0; min_operation < n; ++ min_operation) {
			if (dfs(n, 0, input)) {
				break;
			}
		}
		printf("Case %d: %d\n", cases ++, min_operation);	
	}
	return 0;
}


你可能感兴趣的:(解题报告,图论)