hdu 4511-AC自动机+DP

题目链接:点击打开链接

 

解题思路:根据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;
} 

 

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值