程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> C++入門知識 >> HDU - 4511 小明系列故事――女友的考驗(AC自動機+DP)

HDU - 4511 小明系列故事――女友的考驗(AC自動機+DP)

編輯:C++入門知識

HDU - 4511 小明系列故事――女友的考驗(AC自動機+DP)


Description

  終於放寒假了,小明要和女朋友一起去看電影。這天,女朋友想給小明一個考驗,在小明正准備出發的時候,女朋友告訴他,她在電影院等他,小明過來的路線必須滿足給定的規則:
  1、假設小明在的位置是1號點,女朋友在的位置是n號點,則他們之間有n-2個點可以走,小明每次走的時候只能走到比當前所在點編號大的位置;
  2、小明來的時候不能按一定的順序經過某些地方。比如,如果女朋友告訴小明不能經過1 -> 2 -> 3,那麼就要求小明來的時候走過的路徑不能包含有1 -> 2 -> 3這部分,但是1 -> 3 或者1 -> 2都是可以的,這樣的限制路徑可能有多條。
  這讓小明非常頭痛,現在他把問題交給了你。
  特別說明,如果1 2 3這三個點共線,但是小明是直接從1到3然後再從3繼續,那麼此種情況是不認為小明經過了2這個點的。
  現在,小明即想走最短的路盡快見到女朋友,又不想打破女朋友的規定,你能幫助小明解決這個問題嗎?

Input

  輸入包含多組樣例,每組樣例首先包含兩個整數n和m,其中n代表有n個點,小明在1號點,女朋友在n號點,m代表小明的女朋友有m個要求;
  接下來n行每行輸入2個整數x 和y(x和y均在int范圍),代表這n個點的位置(點的編號從1到n);
  再接著是m個要求,每個要求2行,首先一行是一個k,表示這個要求和k個點有關,然後是順序給出的k個點編號,代表小明不能走k1 -> k2 -> k3 ……-> ki這個順序的路徑;
  n 和 m等於0的時候輸入結束。

   [Technical Specification]
  2 <= n <= 50
  1 <= m <= 100
  2 <= k <= 5

Output

  對於每個樣例,如果存在滿足要求的最短路徑,請輸出這個最短路徑,結果保留兩位小數;否則,請輸出”Can not be reached!” (引號不用輸出)。

Sample Input

 3 1
1 1
2 1
3 1
2
1 2

2 1
0 0
1 1
2 
1 2

5 3
0 0
5 3
1 2
1 22
5 21
3
1 2 3
2 
4 5
2
1 5

0 0 

Sample Output

 2.00
Can not be reached!
21.65 
思路:設dp[i][j]表示到第i個點,自動機狀態到j的最小步數,注意的是因為我們是根據不合法的路徑構造自動機的,所以我們是不能走到某一條路徑的末尾的,根據這點來記錄我們的終止條件

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
using namespace std;
const double inf = 1e20;

pair p[100];
int n;
double dp[55][1000];

double dis(pair a, pair b) {
	  return sqrt((double)(1.0 * a.first - b.first) * (1.0 * a.first - b.first) + (double)(1.0 * a.second - b.second)*(1.0 * a.second - b.second));
}

struct Tie {
	int nxt[1000][55], fail[1000], end[1000];
	int root, cnt;

	int newNode() {
		for (int i = 1; i <= n; i++) 
			nxt[cnt][i] = -1;
		end[cnt++] = 0;
		return cnt - 1;
	}

	void init() {
		cnt = 0;
		root = newNode();
	}

	void insert(int a[], int len) {
		int now = root;
		for (int i = 0; i < len; i++) {
			if (nxt[now][a[i]] == -1)
				nxt[now][a[i]] = newNode();
			now = nxt[now][a[i]];
		}
		end[now] = 1;
	}

	void build() {
		queue q;
		fail[root] = root;
		for (int i = 1; i <= n; i++) {
			if (nxt[root][i] == -1)
				nxt[root][i] = root;
			else {
				fail[nxt[root][i]] = root;
				q.push(nxt[root][i]);
			}
		}

		while (!q.empty()) {
			int now = q.front();
			q.pop();
			end[now] |= end[fail[now]];
			for (int i = 1; i <= n; i++) {
				if (nxt[now][i] == -1)
					nxt[now][i] = nxt[fail[now]][i];
				else {
					fail[nxt[now][i]] = nxt[fail[now]][i];
					q.push(nxt[now][i]);
				}
			}
		}
	}

	void solve() {
		for (int i = 1; i <= n; i++)
			for (int j = 0; j < cnt; j++)
				dp[i][j] = inf;
		dp[1][nxt[root][1]] = 0;
		for (int i = 1; i < n; i++) 
			for (int j = 0; j < cnt; j++) 
				if (dp[i][j] < inf) {
					for (int k = i+1; k <= n; k++) {
						int cur = nxt[j][k];
						if (end[cur]) continue;
						dp[k][cur] = min(dp[k][cur], dp[i][j] + dis(p[i], p[k]));
					}
				}

		double ans = inf;
		for (int i = 0; i < cnt; i++) 
			if (dp[n][i] < inf) 
				ans = min(ans, dp[n][i]);

		if (ans == inf) 
			printf("Can not be reached!\n");
		else printf("%.2lf\n", ans);
	}
} ac;

int a[10];

int main() {
	int m;
	while (scanf("%d%d", &n, &m) != EOF && n + m) {
		for (int i = 1; i <= n; i++) 
			scanf("%d%d", &p[i].first, &p[i].second);
		ac.init();

		int k;
		while (m--) {
			scanf("%d", &k);
			for (int i = 0; i < k; i++)
				scanf("%d", &a[i]);
			ac.insert(a, k);
		}

		ac.build();
		ac.solve();
	}
	return 0;
}




  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved