hdu3247Resource Archiver(ac自动机+spfa)

链接

这题没想到怎么做,问了下p队长,大悟。。

先求出任意两串的在trie树上的最短距离,期间是不能走到不合法的地方,我是用spfa求得,在更新和加入节点时判断一下是不是合法位置。

求出最短距离之后,找出一条从0出发遍历所有串的最短距离,可以dp出,dp[i][j]表示当前状态以节点j串结尾的最短距离。

枚举一下最后结尾的为哪一个串时距离最短。

  1 #include <iostream>
  2 #include<cstdio>
  3 #include<cstring>
  4 #include<algorithm>
  5 #include<stdlib.h>
  6 #include<vector>
  7 #include<cmath>
  8 #include<queue>
  9 #include<set>
 10 using namespace std;
 11 #define N 60010
 12 #define M 10010
 13 #define LL long long
 14 #define INF 0xfffffff
 15 const double eps = 1e-8;
 16 const double pi = acos(-1.0);
 17 const double inf = ~0u>>2;
 18 const int child_num = 2;
 19 int w[15][15];
 20 bool vis[N];
 21 int dis[N];
 22 class AC
 23 {
 24     private:
 25     int ch[N][child_num];
 26     int fail[N];
 27     int Q[N];
 28     int val[N],vv[N];
 29     int id[127];
 30     int sz ;
 31     int po[12];
 32     int dp[2110][12];
 33     public:
 34     void init()
 35     {
 36         fail[0] = 0;
 37         id['1'] = 1;
 38         id['0'] = 0;
 39     }
 40     void reset()
 41     {
 42         memset(ch[0],0,sizeof(ch[0]));
 43         memset(val,0,sizeof(val));
 44         memset(vv,0,sizeof(vv));
 45         sz=1;
 46     }
 47     void insert(char *a ,int key)
 48     {
 49         int p =0 ;
 50         for( ; *a ; a++)
 51         {
 52             int d = id[*a];
 53             if(ch[p][d]==0)
 54             {
 55                 memset(ch[sz],0,sizeof(ch[sz]));
 56                 ch[p][d] = sz++;
 57             }
 58             p = ch[p][d];
 59         }
 60         if(key!=-1)
 61         {
 62             val[p] = 1<<(key-1);
 63             po[key] = p;
 64         }
 65         else
 66         {
 67             vv[p] = 1;
 68         }
 69     }
 70     void construct()
 71     {
 72         int i,head=0,tail = 0;
 73         for(i = 0; i < child_num ; i++)
 74         if(ch[0][i])
 75         {
 76             fail[ch[0][i]] = 0;
 77             Q[tail++] = ch[0][i];
 78         }
 79         while(head!=tail)
 80         {
 81             int u = Q[head++];
 82             vv[u]|=vv[fail[u]];
 83             val[u]|=val[fail[u]];
 84             for(i = 0 ;i < child_num ; i++)
 85             {
 86                 if(ch[u][i])
 87                 {
 88                     fail[ch[u][i]] = ch[fail[u]][i];
 89                     Q[tail++] = ch[u][i];
 90                 }
 91                 else ch[u][i] = ch[fail[u]][i];
 92             }
 93         }
 94     }
 95     int spfa(int st,int ed)
 96     {
 97         int i;
 98         memset(vis,0,sizeof(vis));
 99         for(i = 0; i <= sz ;i++)
100         dis[i] = INF;
101         dis[st] = 0;
102         vis[st] = 1;
103         queue<int>q;
104         q.push(st);
105         while(!q.empty())
106         {
107             int u = q.front();
108             q.pop();
109             for(i = 0 ; i < child_num; i++)
110             {
111                 int v = ch[u][i];
112                 if(vv[v]) continue;
113                 dis[v] = min(dis[v],dis[u]+1);
114                 //if(st == 4&&ed==8)
115                 //cout<<v<<" "<<dis[v]<<" "<<u<<endl;
116                 if(!vis[v])
117                 {
118                     vis[v] = 1;
119                     q.push(v);
120                 }
121             }
122         }
123         return dis[ed];
124     }
125     void find_dis(int n)
126     {
127         int i,j;
128         po[0] = 0;
129         for(i = 1; i <= n ;i++)
130         {
131             w[0][i] = w[i][0] = spfa(0,po[i]);
132             //cout<<w[0][i]<<endl;
133         }
134         for(i = 1; i <= n; i++)
135             for(j = 1 ; j <= n ;j++)
136             {
137                 w[i][j] = spfa(po[i],po[j]);
138                // cout<<w[i][j]<<" "<<i<<" "<<j<<endl;
139             }
140     }
141     void work(int n)
142     {
143         int i,j,g;
144         for(i = 0 ; i < (1<<n) ; i++)
145             for(j = 0;j <= n; j++)
146             dp[i][j] = INF;
147         dp[0][0] = 0;
148         for(i = 0 ;i < (1<<n) ; i++)
149         {
150             for(j = 0 ;j <= n ;j++)
151             {
152                 for(g = 0 ; g <= n ;g++)
153                 {
154                     if((1<<(g-1))&i) continue;
155                     dp[i+(1<<(g-1))][g] = min(dp[i+(1<<(g-1))][g],dp[i][j]+w[j][g]);
156                 }
157             }
158         }
159         int ans = INF;
160         for(i = 1 ; i <= n ; i++)
161         ans = min(ans,dp[(1<<n)-1][i]);
162         cout<<ans<<endl;
163     }
164 }ac;
165 char vir[50010],re[1010];
166 int main()
167 {
168     int n,m,i;
169     ac.init();
170     while(scanf("%d%d",&n,&m)&&n&&m)
171     {
172         ac.reset();
173         for(i = 1; i <= n ;i++)
174         {
175             scanf("%s",re);
176             ac.insert(re,i);
177         }
178         while(m--)
179         {
180             scanf("%s",vir);
181             ac.insert(vir,-1);
182         }
183         ac.construct();
184         ac.find_dis(n);
185         ac.work(n);
186     }
187     return 0;
188 }
View Code

 

posted @ 2014-05-25 10:11  _雨  阅读(197)  评论(0编辑  收藏  举报