hdoj 3058 ac自动机+高斯消元

来源:互联网 发布:知无知 谌洪果视频 编辑:程序博客网 时间:2024/06/05 00:55

这道题和zoj2619的实质性是一样的,只不过这个中字符串的个数比较多,所以就需要建立自动机了,我的zoj上的题是直接用kmp的,只不过这道题麻烦却让我纠结了几天啊,感觉有的时候脑子就是不太会拐弯,就是不会转化的。

不知道怎么用ac自动机去转化然后去建立数组,然后就今天下午在这里改了几乎一下午,挺搞笑的,一有思路就在那里改,然后改的多了就又回去找最原始的代码继续弄,好歹还是改出来了,现在自己想想思路都是迷糊的啊,其实是看了别人的得出的方程然后启发下改出来的。

思路:关于ac自动机的建立我就不罗嗦了,就是关于方程的转换问题,一开始我想的是在所有的字符串中相同的长度的字符进行累加放在一行,但是一直wa,然后就没有什么想法,到后来改为对没有个节点进行标记,一个节点记录一行,然后就AC了,不过当时只顾着似乎对的兴奋没有怎么改数组的大小然后RE了一次,囧啊!下面是代码,可能改的有点乱啊!

/////////////////////////////////////////////////////////////////////////// File Name: 21631.cpp// Author: wang// mail: // Created Time: 2013-8-8 8:29:19/////////////////////////////////////////////////////////////////////////#include <cstdio>#include <cstdlib>#include <climits>#include <cstring>#include <cmath>#include <algorithm>#include<iostream>#include<queue>#include <map>using namespace std;typedef long long ll;#define INF (INT_MAX/10)#define SQR(x) ((x)*(x))#define rep(i, n) for (int i=0; i<(n); ++i)#define repf(i, a, b) for (int i=(a); i<=(b); ++i)#define repd(i, a, b) for (int i=(a); i>=(b); --i)#define clr(ar,val) memset(ar, val, sizeof(ar))#define pb(i) push_back(i)#define exp 0.000000001#define N 101double a[N][N];int n,m,tot;char s[20];bool vis[50];vector<int>vec;//存储出现的字符struct node{bool sign;int len,fal;int next[26];};node ac[10000];void init(){ac[0].sign=false;tot=0;ac[0].len=0; ac[0].fal=0;memset(ac[0].next,-1,sizeof(ac[0].next));memset(a,0,sizeof(a));memset(vis,false,sizeof(vis));vec.clear();}void tree(){int len=strlen(s);int u=0;rep(i,len){int x=s[i]-'A';if(ac[u].next[x]==-1){            ++tot; ac[tot].sign=false; memset(ac[tot].next,-1,sizeof(ac[tot].next));ac[u].next[x]=tot;}u=ac[u].next[x];if(i==len-1) ac[u].sign=true;//代表有以这个结尾的}}int fail(int u,int k){if(ac[u].next[k]!=-1) return ac[u].next[k];if(u==0) return 0;return fail(ac[u].fal,k);}void bulid(){queue<int>q;q.push(0);while(!q.empty()){int x=q.front(); q.pop();rep(i,26)if(ac[x].next[i]!=-1){q.push(ac[x].next[i]);if(x==0) ac[ac[x].next[i]].fal=0;else ac[ac[x].next[i]].fal=fail(ac[x].fal,i);}}int len=0;q.push(0);while(!q.empty()){int x=q.front(); q.pop();if(ac[ac[x].fal].sign==true)ac[x].sign=true;if(ac[x].sign==false)ac[x].len=len++;rep(i,26)if(ac[x].next[i]!=-1)q.push(ac[x].next[i]);}}void work()//如果为true就代表是结尾就不要加了{      queue<int>q; q.push(0); int len=vec.size(); int Max=0; while(!q.empty()) { int x=q.front(); q.pop(); int l=ac[x].len; Max=max(Max,l); a[l][l]-=n;//等号左边的,为负号 a[l][0]+=(n-len);//会变为0的 rep(j,len) { int u=x; int y=vec[j];  int sign=0; while(true) { if(ac[u].next[y]!=-1) { if(ac[ac[u].next[y]].sign==false)                     a[l][ac[ac[u].next[y]].len]+=1; sign=1; break; } if(ac[u].next[y]!=-1) sign=1; if(u==0) break; u=ac[u].fal; } if(sign==0) a[l][0]++; } rep(i,26)  if(ac[x].next[i]!=-1 && ac[ac[x].next[i]].sign==false) q.push(ac[x].next[i]); } repf(i,0,Max) a[i][Max+1]=n; n=Max+1,m=Max+2;}void guess(){rep(i,n){int k=-1; repf(j,i,n-1)if(a[j][i]!=0){k=j; break;}if(k==-1) continue;if(k!=i)rep(j,m) swap(a[i][j],a[k][j]);rep(j,n){if(j!=i){double x=a[i][i],y=a[j][i];rep(k,m)a[j][k]=a[j][k]-a[i][k]*y/x;}}}if(fabs(0-a[0][0])<exp) printf("%0.00\n");else printf("%0.2lf\n",-a[0][m-1]*1.0/a[0][0]);}void solve(){init();rep(i,m){scanf("%s",s); tree();int len=strlen(s);rep(j,len) if(vis[s[j]-'A']==false){vec.pb(s[j]-'A'); vis[s[j]-'A']=true;}}bulid();//rep(i,tot+1) cout<<ac[i].sign<<endl;work();guess();}int main(){int test;scanf("%d",&test);while(test--){scanf("%d%d",&n,&m);        solve();}}


 

原创粉丝点击