HDU 4511 小明系列故事——女友的考验(自动机+DP)

来源:互联网 发布:淘宝知网查重可靠吗 编辑:程序博客网 时间:2024/04/29 14:41
Problem 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 11 12 13 121 22 10 01 12 1 25 30 05 31 21 225 2131 2 32 4 521 50 0
 

Sample Output
2.00Can not be reached!21.65
 
状态也很好想,设dp[i][j]代表走到i节点,在自动机上状态为j时的最小花费
#include<cstdio>#include<cstring>#include<algorithm>#include<vector>#include<string>#include<iostream>#include<queue>#include<cmath>#include<map>#include<stack>#include<bitset>using namespace std;#define REPF( i , a , b ) for ( int i = a ; i <= b ; ++ i )#define REP( i , n ) for ( int i = 0 ; i < n ; ++ i )#define CLEAR( a , x ) memset ( a , x , sizeof a )typedef long long LL;typedef pair<int,int>pil;const double INF = 1e20;struct node{    int x,y;}e[110];double dp[55][1100];int n,m;double dis(node l1,node l2){    return sqrt((double)(1.0*l1.x-l2.x)*(1.0*l1.x-l2.x)+(double)(1.0*l1.y-l2.y)*(1.0*l1.y-l2.y));}struct AC{     int next[1100][55];     int fail[1100];     int ed[1100];     int root,L;     int newnode()     {         for(int i=1;i<=n;i++)            next[L][i]=-1;         ed[L++]=0;         return L-1;     }     void init()     {         L=0;         root=newnode();     }     void Insert(char buf[])     {         int len=strlen(buf);         int now=root;         for(int i=0;i<len;i++)         {             int id=buf[i]-'0';             if(next[now][id]==-1)                next[now][id]=newnode();             now=next[now][id];         }         ed[now]=1;     }     void Build_AC()     {         queue<int>q;         fail[root]=root;         for(int i=1;i<=n;i++)         {             if(next[root][i]==-1)                next[root][i]=root;             else             {                fail[next[root][i]]=root;                q.push(next[root][i]);             }         }         while(!q.empty())         {             int now=q.front();             q.pop();             ed[now]|=ed[fail[now]];             for(int i=1;i<=n;i++)             {                 if(next[now][i]==-1)                    next[now][i]=next[fail[now]][i];                 else                 {                    fail[next[now][i]]=next[fail[now]][i];                    q.push(next[now][i]);                 }             }         }     }     void  solve()     {         for(int i=1;i<=n;i++)            for(int j=0;j<L;j++) dp[i][j]=INF;         dp[1][next[root][1]]=0;//开始时在1位置,所以节点不在自动机的root节点了         for(int i=1;i<=n;i++)         {             for(int j=0;j<L;j++)             {                 if(dp[i][j]==INF) continue;                 for(int k=1;k<=n;k++)                 {                     int x=next[j][k];                     if(ed[x]) continue;                     dp[k][x]=min(dp[k][x],dp[i][j]+dis(e[i],e[k]));                 }             }         }         double ans=INF;         for(int i=0;i<L;i++)            ans=min(ans,dp[n][i]);         if(ans==INF) puts("Can not be reached!");         else printf("%.2f\n",ans);     }};AC A;int main(){    char str[10];int x,k;    while(~scanf("%d%d",&n,&m))    {        if(n+m==0) break;        A.init();        REPF(i,1,n)          scanf("%d%d",&e[i].x,&e[i].y);        while(m--)        {            int l=0;            scanf("%d",&k);            for(int i=0;i<k;i++)            {                scanf("%d",&x);                str[l++]=x+'0';            }            str[l]='\0';            A.Insert(str);        }        A.Build_AC();        A.solve();    }    return 0;}/*3 11 12 13 121 2*/


0 0