1. 程式人生 > >hdu1560 IDA* 進階搜尋

hdu1560 IDA* 進階搜尋

傳送門:http://acm.hdu.edu.cn/showproblem.php?pid=1560

題意大致就是:給你幾個字元序列,然後問你一個最短的序列的長度:這個序列要可以組成那幾個字元序列

思路:我一開始想的是雙拓撲排序來構建優先關係,但後來失敗了。

 

         這道題的思路其實可以理解為一種模擬,假設這裡有一個長度為deep的區間,(deep為之前序列的最長的長度)那麼我們要做的的就是模擬每個格子應該填什麼才能讓這個格子最短,於是我們可以進行dfs模擬,先假設第一個格子是a,如果各序列裡有滿足第一個字元是a的那麼該序列的指標向下移動,其餘不變,然後在模擬第二個格子,。。。。其中在模擬時為了剪枝使用了個預估函式,這個預估函式作用是預判理想情況下這個格子夠不夠用,如果理想情況都不夠那麼說明這個方法錯誤,返回,改變方法,如果所有的方法所得到的格子長度都比deep大,那麼退出,deep++,再進行同樣的過程。知道找到符合長度等於deep的情況,這個過程就是IDA*演算法的過程。

反思:我在這道題的理解還是不到位,沒有想到這道題其實本質上還是一種列舉的問題,這個點才是這個題的核心思想,你只要想到這個題的思路是列舉,才能想到搜尋的思路,

程式碼:

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<string>

using namespace std;

int n, deep;
char c[10] = "ACGT";
string a[10];
int pos[10];

int geth()//獲取剩下的字元序列要想全部匹配還需要的最大長度;
{
		int ans = 0;
		for (int i = 1; i <= n; i++)
				ans = max(ans, (int)a[i].size()-pos[i]);
		return ans;
}

int dfs(int step)
{
		if (step + geth() > deep)
				return 0;
		if (geth() == 0)
				return 1;
		int tem[10];
		for (int i = 0; i < 4; i++)
		{
				int flag = 0;
				for (int j = 1; j <= n; j++)
						tem[j] = pos[j];
				for (int j = 1; j <= n; j++)
				{
						if (a[j][pos[j]] == c[i])
						{
								flag = 1;
								pos[j]++;
						}
				}
				if (flag)
				{
						if (dfs(step + 1))
								return 1;
						for (int j = 1; j <= n; j++)
								pos[j] = tem[j];
				}
		}
		return 0;
}

int main()
{
		int t;
		scanf("%d", &t);
		while (t--)
		{
				//memset()
				scanf("%d", &n);
				deep = 0;
				for (int i = 1; i <= n; i++)
				{
						cin >> a[i];
						deep = max(deep, (int)a[i].size());
						pos[i] = 0;
				}
				while (1)
				{
						if (dfs(0))  break;
						deep++;
				}
				printf("%d\n", deep);
				for (int i = 1; i <= n; i++)
						a[i].clear();
		}
		//system("pause");
		return 0;
}