• HDU3247 Resource Archiver [AC自动机+DP]


      一道纠结了好久的题,主要是因为一开始思路就想错了,还按着错误的思路想了好久。。。

      题目大意就是要找一个最短的字符串,包含所有的合法单词并且不包含所有的非法单词。

      题目中给的非法单词非常多,但是合法单词很少,很容易想到用状态压缩来做。我一开始想到的是把每个合法单词当作一个点,然后用哈密顿回路来做,想了半天才发现这个思路明显是错误的。。。。。。

      正确的做法是把所有可以作为合法单词结尾的点选出来,BFS出每两点之间的距离,每个点都会有一个压缩状态标记这个点可以作为哪几个单词的结尾,然后DP就可以了。

      d[state][v]表示最后一步在v时到达state这个状态需要的最小长度,方程为d[stat|flag[pnt[v]]][v]=min(d[stat|flag[pnt[v]]][v],d[stat][u]+map[u][v]),其中flag[pnt[v]]表示以v这个点的状态。

    #include <stdio.h>
    #include <string.h>
    #define INF 0x3f3f3f3f
    #define MAXN 60005
    char s[1002];
    int n,m;
    int next[MAXN][2],fail[MAXN],flag[MAXN],pos;
    int newnode(){
        next[pos][0]=next[pos][1]=0;
        fail[pos]=flag[pos]=0;
        return pos++;
    }
    void insert(char *s,int id){
        int p=0;
        for(int i=0;s[i];i++){
            int k=s[i]-'0',&x=next[p][k];
            p=x?x:x=newnode();
        }
        if(id==-1)flag[p]=-1;
        else flag[p]|=(1<<id);
    }
    int q[MAXN],front,rear;
    void makenext(){
        q[front=rear=0]=0,rear++;
        while(front<rear){
            int u=q[front++];
            for(int i=0;i<2;i++){
                int v=next[u][i];
                if(v==0)next[u][i]=next[fail[u]][i];
                else q[rear++]=v;
                if(v&&u){
                    fail[v]=next[fail[u]][i];
                    if(flag[fail[v]]==-1)flag[v]=-1;
                    else flag[v]|=flag[fail[v]];
                }
            }
        }
    }
    #define MAXM 50
    int d[1025][MAXM],pnt[MAXM],ps,map[MAXM][MAXM],dis[MAXN];
    inline int min(int x,int y){return x<y?x:y;}
    void bfs(int p){
        for(int i=0;i<pos;i++)dis[i]=INF;
        q[front=rear=0]=pnt[p],rear++;
        dis[pnt[p]]=0;
        while(front<rear){
            int u=q[front++];
            for(int i=0;i<2;i++){
                int v=next[u][i];
                if(flag[v]<0||dis[v]!=INF)continue;
                dis[v]=dis[u]+1;
                q[rear++]=v;
            }
        }
        for(int i=0;i<ps;i++)map[p][i]=dis[pnt[i]];
    }
    int dp(){
        for(int i=0;i<(1<<n);i++)for(int u=0;u<ps;u++)d[i][u]=INF;
        d[0][0]=0;
        for(int i=0;i<(1<<n);i++){
            for(int u=0;u<ps;u++){
                if(d[i][u]==INF)continue;
                for(int v=0;v<ps;v++)
                    d[i|flag[pnt[v]]][v]=min(d[i|flag[pnt[v]]][v],d[i][u]+map[u][v]);
            }
        }
        int ans=INF;
        for(int i=0;i<ps;i++)
            ans=min(ans,d[(1<<n)-1][i]);
        return ans;
    }
    int main(){
      //  freopen("test.in","r",stdin);
        while(scanf("%d%d",&n,&m),n||m){
            pos=0;newnode();
            for(int i=0;i<n;i++){
                scanf("%s",s);
                insert(s,i);
            }
            for(int i=0;i<m;i++){
                scanf("%s",s);
                insert(s,-1);
            }
            makenext();
            ps=0;
            for(int i=0;i<pos;i++)
                if(i==0||flag[i]>0)pnt[ps++]=i;
            for(int i=0;i<ps;i++)
                bfs(i);
            printf("%d\n",dp());
        }
        return 0;
    }

      

  • 相关阅读:
    Python 字典(Dictionary)
    Python函数
    Python 模块
    一步步学习SPD2010--第二章节--处理SP网站(9)---- 关键点
    一步步学习SPD2010--第二章节--处理SP网站(8)---- 保存和使用网站模板
    一步步学习SPD2010--第二章节--处理SP网站(7)---- 导航网站的内容
    一步步学习SPD2010--第二章节--处理SP网站(6)---- 探索SP网站
    一步步学习SPD2010--第二章节--处理SP网站(5)附—升级自定义SP网站的复杂性
    一步步学习SPD2010--第二章节--处理SP网站(5)--重置网站模板
    一步步学习SPD2010--第二章节--处理SP网站(4)--删除SP网站
  • 原文地址:https://www.cnblogs.com/swm8023/p/2634196.html
Copyright © 2020-2023  润新知