题目链接:点击打开链接
解题思路:根据m点的限制构造树。用dp【i】【j】表示到i位置且在自动机上j节点位置时的最小距离。然后用floyed就OK了。
代码:
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<queue>
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
using namespace std;
typedef long long ll;
const int mx =1e3+10;
const double inf = 1e18;
int n,m,a[20];
struct node{
int x,y;
node(){}
node(int v,int u):x(v),y(u){}
}s[mx/10];
double dis(node A,node B){ return sqrt(pow(1.0*A.x-1.0*B.x,2)+pow(1.0*A.y-1.0*B.y,2)); }
struct tree{
int nxt[mx][55],fail[mx],cnt,root;
bool end[mx];
double dp[55][mx];
int newnode(){
memset(nxt[cnt],-1,sizeof(nxt[cnt]));
end[cnt] = 0;
return cnt++;
}
void insert(int *p,int len){
int now = root;
for(int i=0;i<len;i++){
if(nxt[now][p[i]]==-1) nxt[now][p[i]] = newnode();
now = nxt[now][p[i]];
}
end[now] = 1;
}
void bulid(){
queue <int> skt;
for(int i=1;i<=n;i++){
if(nxt[root][i]==-1) nxt[root][i] = root;
else{
fail[nxt[root][i]] = root;
skt.push(nxt[root][i]);
}
}
while(!skt.empty()){
int now = skt.front();
skt.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];
skt.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 po = nxt[j][k];
if(!end[po]) dp[k][po] = min(dp[k][po],dp[i][j]+dis(s[i],s[k]));
}
}
}
}
double ans = inf;
for(int i=0;i<cnt;i++)
ans = min(dp[n][i],ans);
if(ans == inf) puts("Can not be reached!");
else printf("%.2lf\n",ans);
}
}ac;
int main(){
while(scanf("%d%d",&n,&m)&&n+m){
for(int i=1;i<=n;i++) scanf("%d%d",&s[i].x,&s[i].y);
int k ;
ac.cnt = 0,ac.root = ac.newnode();
ac.fail[0] = 0;
while(m--){
scanf("%d",&k);
for(int i=0;i<k;i++) scanf("%d",a+i);
ac.insert(a,k);
}
ac.bulid();
ac.solve();
}
return 0;
}