HDU 4511小明シリーズストーリー——彼女の試練(ACオートマチック+DP)

21639 ワード

小明シリーズの物語——彼女の試練
Time Limit: 500/200 MS (Java/Others)    Memory Limit: 65535/32768 K (Java/Others)Total Submission(s): 654    Accepted Submission(s): 136
Problem Description
やっと冬休みになったので、明ちゃんは彼女と一緒に映画を見に行きます.この日、彼女は明ちゃんに試練を与えようとしたが、明ちゃんが出発する準備をしている間に、彼女は映画館で彼を待っていて、明ちゃんが来たルートは与えられたルールを満たさなければならないと言った.
1、仮に明ちゃんがいる位置が1番のポイントで、彼女がいる位置がn番のポイントであれば、彼らの間にはn-2つのポイントがあり、明ちゃんは歩くたびに現在のポイントより大きい位置にしか歩けない.
2、明ちゃんが来るときは、一定の順序でどこかを通ることはできません.例えば、彼女が明ちゃんに1->2->3を通ってはいけないと言ったら、明ちゃんが来たときに通った経路には1->2->3という部分は含まれてはいけないと要求しますが、1->3か1->2は可能で、このような制限経路は複数あるかもしれません.
これは明ちゃんをとても頭が痛くて、今彼はあなたに問題を渡しました.
特に、1 2 3という3つの点が共線であるが、明ちゃんが直接1から3まで続いている場合、明ちゃんが2という点を通ったとは思えない.
今、明ちゃんは最短の道を歩いてできるだけ早く彼女に会いたいし、彼女の規定を破りたくないので、明ちゃんを助けてこの問題を解決することができますか?
 
 
Input
入力には複数のサンプルが含まれ、各サンプルにはまず2つの整数nとmが含まれ、そのうちnはn個の点を表し、明は1番の点で、彼女はn番の点で、mは明の彼女を表してm個の要求がある.
次に、n行毎に2つの整数xとy(xとyはintの範囲)を入力し、このn点の位置(点の番号は1からn)を表す.
次にm個の要求で、各要求2行、まず1行はkで、この要求がk個の点と関係があることを表して、それから順序が与えたk個の点番号で、明ちゃんがk 1->k 2->k 3......->kiという順序の経路を歩けないことを表します.
nとmが0に等しいときに入力が終了します.
  
[Technical Specification]
  2 <= n <= 50
  1 <= m <= 100
  2 <= k <= 5
 
 
Output
各サンプルについて、要求を満たす最短パスがある場合は、この最短パスを出力し、結果は2桁の小数を保持します.そうでなければ、「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
 
 
いくつかの経路は歩けず、ACオートマチックによって状態遷移が得られる.
その後dp[i][j]はi点で,状態はjの距離を表す.
 
ネット上でfloyedのやり方を見て、最後にchaすることができることを発見して、経路は2つの点だけを見ることができません.例えば1->3 1->2->3  これでは1は3にはなりません.
 
 
座標intが減算とintがオーバーフローするのでdoubleを直接使用するのが望ましい.
 
  1 /* ***********************************************
  2 Author        :kuangbin
  3 Created Time  :2014/3/2 22:07:17
  4 File Name     :E:\2014ACM\    \AC   \HDU4511.cpp
  5 ************************************************ */
  6 
  7 #include <stdio.h>
  8 #include <string.h>
  9 #include <iostream>
 10 #include <algorithm>
 11 #include <vector>
 12 #include <queue>
 13 #include <set>
 14 #include <map>
 15 #include <string>
 16 #include <math.h>
 17 #include <stdlib.h>
 18 #include <time.h>
 19 using namespace std;
 20 const double INF = 1e20;
 21 int n;
 22 
 23 pair<int,int> p[100];
 24 double dis(pair<int,int>a,pair<int,int>b)//     int
 25 {
 26     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));
 27 }
 28 double dp[55][1000];
 29 void CheckMin(double &a,double b)
 30 {
 31     a = min(a,b);
 32 }
 33 struct Trie
 34 {
 35     int next[1000][55],fail[1000],end[1000];
 36     int root,L;
 37     int newnode()
 38     {
 39         for(int i = 1; i <= n;i++)
 40             next[L][i] = -1;
 41         end[L++] = 0;
 42         return L-1;
 43     }
 44     void init()
 45     {
 46         L = 0;
 47         root = newnode();
 48     }
 49     void insert(int a[],int cnt)
 50     {
 51         int now = root;
 52         for(int i  = 0;i < cnt;i++)
 53         {
 54             if(next[now][a[i]] == -1)
 55                 next[now][a[i]] = newnode();
 56             now = next[now][a[i]];
 57         }
 58         end[now] = 1;
 59     }
 60     void build()
 61     {
 62         queue<int>Q;
 63         fail[root] = root;
 64         for(int i = 1;i <= n;i++)
 65             if(next[root][i] == -1)
 66                 next[root][i] = root;
 67             else 
 68             {
 69                 fail[next[root][i]] = root;
 70                 Q.push(next[root][i]);
 71             }
 72         while(!Q.empty())
 73         {
 74             int now = Q.front();
 75             Q.pop();
 76             end[now] |= end[fail[now]];
 77             for(int i = 1;i <= n;i++)
 78                 if(next[now][i] == -1)
 79                     next[now][i] = next[fail[now]][i];
 80                 else
 81                 {
 82                     fail[next[now][i]] = next[fail[now]][i];
 83                     Q.push(next[now][i]);
 84                 }
 85         }
 86 
 87     }
 88     void solve()
 89     {
 90         for(int i = 1;i <= n;i++)
 91             for(int j = 0;j < L;j++)
 92                 dp[i][j] = INF;
 93         dp[1][next[root][1]] = 0;
 94         for(int i = 1;i < n;i++)
 95             for(int j = 0;j < L;j++)
 96                 if(dp[i][j] < INF)
 97                 {
 98                     for(int k = i+1;k <= n;k++)
 99                     {
100                         int ss = next[j][k];
101                         if(end[ss])continue;
102                         CheckMin(dp[k][ss],dp[i][j] + dis(p[i],p[k]));
103                     }
104                 }
105         double ans = INF;
106         for(int i = 0;i < L;i++)
107             if(dp[n][i] < INF)
108                 CheckMin(ans,dp[n][i]);
109         if(ans == INF)printf("Can not be reached!
"); 110 else printf("%.2f
",ans); 111 } 112 }ac; 113 114 int a[10]; 115 int main() 116 { 117 //freopen("in.txt","r",stdin); 118 //freopen("out.txt","w",stdout); 119 int m; 120 while(scanf("%d%d",&n,&m) == 2) 121 { 122 if(n == 0 && m == 0)break; 123 for(int i = 1;i <= n;i++) 124 scanf("%d%d",&p[i].first,&p[i].second); 125 ac.init(); 126 int k; 127 while(m--) 128 { 129 scanf("%d",&k); 130 for(int i = 0;i < k;i++) 131 scanf("%d",&a[i]); 132 ac.insert(a,k); 133 } 134 ac.build(); 135 ac.solve(); 136 } 137 return 0; 138 }