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 }