[c]代码库
/*
2013腾讯马拉松初赛第2场
1002 小明系列故事——女友的考验
Time Limit: 0.2 Seconds Memory Limit: 32768K
终于放寒假了,小明要和女朋友一起去看电影。这天,女朋友想给小明一个考验,在小明正准备出发的时候,女朋友告诉他,她在电影院等他,小明过来的路线必须满足给定的规则:
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
*/
/*
解题报告:
这题初看没什么头续,看到了这些路径,然后又想看的数据范围,K很好,想到了Trie,然后又想到了字符串匹配,于是想到了AC自动机。
想到了AC自动机,这题就好做了,就是一个AC自动机DP嘛。
把题目给的非法路径构成一棵Trie树,然做跑一次AC自动机。
然后做DP
dp[i][j]代表在第i个点自动机状态在j的最小距离。
然后枚举可走的点去转移就行了。
自动机状态最多有5*100个。
总的DP状态有50*500,每一个转移是50,最后的复杂度是50*50*500
*/
#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() {
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[n][i] < ans)ans = dp[n][i];
}
if(dblcmp(INF - ans) != 0)printf("%.2f\n", ans);
else puts("Can not be reached!");
}
return 0;
}
初级程序员
by: 我的程序员之路 发表于:2013-05-19 20:49:23 顶(0) | 踩(0) 回复
算法果然才是精髓!
回复评论