hdu 4511 AC自动机 + dp
2013-03-26 16:04
453 查看
题目大意:
终于放寒假了,小明要和女朋友一起去看电影。这天,女朋友想给小明一个考验,在小明正准备出发的时候,女朋友告诉他,她在电影院等他,小明过来的路线必须满足给定的规则:
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
解题报告:这题初看没什么头续,看到了这些路径,然后又想看的数据范围,K很好,想到了Trie,然后又想到了字符串匹配,于是想到了AC自动机。
想到了AC自动机,这题就好做了,就是一个AC自动机DP嘛。
把题目给的非法路径构成一棵Trie树,然做跑一次AC自动机。
然后做DP
dp[i][j]代表在第i个点自动机状态在j的最小距离。
然后枚举可走的点去转移就行了。
自动机状态最多有5*100个。
总的DP状态有50*500,每一个转移是50,最后的复杂度是50*50*500
刚刚过题目。
PS:一次AC,很高兴。
转自:http://hi.baidu.com/chenwenwen0210/item/ca0768d039b0f1d793a974c9
检讨:当时做这题的时候没有想到应该用ac自动机。换做当时经常做acm的时候应该能想到。
把题目给的非法路径构成一棵Trie树,然后做跑一次AC自动机。
这题就是一些基础的东西结合。算法本身不难。自己实现一下吧,不套模板。
这份代码用的静态trie较高效。
终于放寒假了,小明要和女朋友一起去看电影。这天,女朋友想给小明一个考验,在小明正准备出发的时候,女朋友告诉他,她在电影院等他,小明过来的路线必须满足给定的规则:
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
解题报告:这题初看没什么头续,看到了这些路径,然后又想看的数据范围,K很好,想到了Trie,然后又想到了字符串匹配,于是想到了AC自动机。
想到了AC自动机,这题就好做了,就是一个AC自动机DP嘛。
把题目给的非法路径构成一棵Trie树,然做跑一次AC自动机。
然后做DP
dp[i][j]代表在第i个点自动机状态在j的最小距离。
然后枚举可走的点去转移就行了。
自动机状态最多有5*100个。
总的DP状态有50*500,每一个转移是50,最后的复杂度是50*50*500
刚刚过题目。
PS:一次AC,很高兴。
#include<stdio.h> #include<math.h> #include<string.h> const int MAX=1005; const int MAXSON=50; struct { int id,next[MAXSON],fail; }node[1000000]; int n,tot; char mod[1000005]; int len[MAX]; int q[1000000]; void clr() { int i; tot++; for(i=0;i<MAXSON;i++) node[tot].next[i]=0; node[tot].id=node[tot].fail=0; } void ins() { int tmp,i,n; int h=0; scanf("%d",&n); while(n--) { scanf("%d",&tmp); tmp--; if(node[h].next[tmp]==0) { clr(); node[h].next[tmp]=tot; } h=node[h].next[tmp]; } node[h].id++; } void get_fail() { int h=0,i; int f=-1,r=0; int tmp,fail,k; q[0]=0; while(f!=r) { tmp=q[++f]; if(node[node[tmp].fail].id>0)//自动机添加一个往前走的东西。错在这里啊,好久没有用AC自动机了 node[tmp].id=1; for(i=0;i<MAXSON;i++) { if(node[tmp].next[i]==0) { fail=node[tmp].fail; node[tmp].next[i]=node[fail].next[i]; continue; } k=node[tmp].next[i]; fail=node[tmp].fail; if(node[fail].next[i]!=k) node[k].fail=node[fail].next[i]; else node[k].fail=0; q[++r]=k; } } } const double EPS=1.0e-8; bool dblcmp(double x) { if(fabs(x)<EPS)return 0; return x<0?-1:1; } struct Point { double x,y; }p[55]; double disPP(Point a,Point b) { double dx=a.x-b.x; double dy=a.y-b.y; return sqrt(dx*dx+dy*dy); } const double INF=1000000000.0*100000000.0; double dp[55][5*110]; int main() { freopen("4511.txt", "r", stdin); int n,m; int i,j,k; while(scanf("%d%d",&n,&m)!=EOF) { if(n==0&&m==0)break; for(i=1;i<=n;i++) { scanf("%lf%lf",&p[i].x,&p[i].y); } tot=-1; clr(); while(m--) { ins(); } get_fail(); for(i=0;i<=n;i++) { for(j=0;j<=tot;j++) { dp[i][j]=INF; } } int h=node[0].next[0]; if(node[h].id>0) { puts("Can not be reached!"); continue; } dp[1][h]=0; double cost=0; for(i=1;i<=n;i++) { for(j=0;j<=tot;j++) { if(dblcmp(dp[i][j]-INF)==0)continue; for(k=i+1;k<=n;k++) { h=node[j].next[k-1]; if(node[h].id)continue; cost=disPP(p[i],p[k])+dp[i][j]; if(cost<dp[k][h])dp[k][h]=cost; } } } double ans=INF; for(i=0;i<=tot;i++) { if(dp [i]<ans)ans=dp [i]; } if(dblcmp(INF-ans)!=0)printf("%.2f\n",ans); else puts("Can not be reached!"); } return 0; }
转自:http://hi.baidu.com/chenwenwen0210/item/ca0768d039b0f1d793a974c9
检讨:当时做这题的时候没有想到应该用ac自动机。换做当时经常做acm的时候应该能想到。
把题目给的非法路径构成一棵Trie树,然后做跑一次AC自动机。
这题就是一些基础的东西结合。算法本身不难。自己实现一下吧,不套模板。
这份代码用的静态trie较高效。
相关文章推荐
- HDU 4511 小明系列故事——女友的考验(AC自动机 + DP)
- HDU 4511 (AC自动机 DP)
- HDU 4511 小明系列故事——女友的考验 (AC自动机 + DP)
- HDU 4511 小明系列故事——女友的考验 (AC自动机 + dp)
- HDU 2457 (AC自动机 DP)
- HDU 2296 Ring (AC自动机 + DP)
- HDU 2825 Wireless Password (AC自动机 + 状态压缩DP)
- hdu 2858 ac自动机 +状态压缩dp
- HDU 4057 Rescue the Rabbit ( AC自动机 + 状态压缩DP )
- HDU-4518 吉哥系列故事——最终数 AC自动机+数位DP
- HDU 4758 Walk Through Squares (AC自动机 + 状压dp)
- HDU 2243 AC自动机->DP->附矩阵乘法板子
- HDU 2825 Wireless Password (AC自动机,DP)
- HDU 3058 Generator [AC自动机+期望DP]
- hdu - 4511 小明系列故事——女友的考验(AC自动机+DP)
- 【HDU】4511 小明系列故事——女友的考验 (AC自动机+DP)
- HDU 2296 Ring [AC自动机 DP 打印方案]
- hdu2825——ac自动机,DP
- hdu 4117 GRE Words (ac自动机 线段树 dp)
- HDU 2825 Wireless Password (AC自动机 + 状压dp)