hdu 4511-AC自动机+DP

来源:互联网 发布:linux查看磁盘使用情况 编辑:程序博客网 时间:2024/04/28 02:21

题目链接:点击打开链接


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



原创粉丝点击