乙個n個資源串,m個病毒串。要求生成乙個字串,包含所有資源串,但不能包含病毒串。問生成字串的最小長度。
首先利用ac自動機求出資源串的狀態轉移關係,因為資源串最多只有十種,因此可以進行狀態壓縮。在利用ac自動機求失配關係的時候(這裡在求失配關係的時候需要將不存在的邊補上),順便求出來狀態包含關係。
求出失配關係以後,首先要將所有的包含資源串的點加入到乙個集合中,針對每個點進行bfs,計算這個點到其他資源點的距離。(由於補全了不存在的邊,因此在進行bfs的時候就可以從乙個資源點轉移到根節點,再轉移到其他資源點。)
計算出距離以後,便可以進行狀壓dp。因為針對每個狀態,可以在資源串的任意點。所有dp陣列需要二維陣列,dp[包含資源狀態][當前點]。然後,只要兩個點之間距離不為-1,就可以進行狀態轉移。
最後,查詢一下所有包含所有資源的dp陣列值,選取最小的即為所求。
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define up(i,l,h) for(int i=l;i#define down(i,h,l) for(int i=h-1;i>=l;i--)
#define w(a) while(a)
#define mem(a,b) memset(a,b,sizeof(a))
#define inf 0x3f3f3f3f
#define ll long long
#define maxn 100010
#define eps 1e-10
#define mod 20090717
using
namespace
std;
struct node ;
int ch[maxn][2];
node val[maxn];
char st[50010];
int path[1010][1010];
int dist[maxn],f[maxn];
int dp[2060][1010];
int sz,ressz;
int n,m,pos;
vector
resvc;
void insert(bool source,bool virus)
u=ch[u][x];
}if(source)
}void getfail()
}w(!q.empty())
q.push(x);
int v=f[r];
f[x]=ch[f[r]][i];
val[x].source|=val[f[x]].source;
val[x].virus|=val[f[x]].virus;}}
}void bfs(int x) }}
}up(i,0,ressz)
}void solve()
int news=val[resvc[k]].source;
if(dp[i|news][k]==-1) else }}
}int ans=inf;
int tar=(1
<1;
up(i,0,ressz)
if(dp[tar][i]!=-1)
ans=min(dp[tar][i],ans);
printf("%d\n",ans);
}int main()
up(j,0,m)
getfail();
resvc.clear();
resvc.push_back(0);
up(i,0,sz)
}ressz=resvc.size();
up(i,0,ressz)
solve();
}}
hdu 2825 AC自動機 狀壓dp
假設乙個字串長為n,現在在j這個位置,此時已經包含了乙個模式串集合 由於m只有10,所有可以用狀壓來表示模式串 到下乙個位置時,一共有26種情況,現在你想知道的是多乙個字母後會多幾個模式串,由於是多匹配問題便想到了ac自動機,而此時只要紀錄走道j這個位置時trie上走到k這個位置。所以狀態便是dp ...
HDU 2825 AC自動機 狀壓DP
給m個字串,要求組成乙個長度為n的字串,至少包含k個給定字串。利用ac自動機,我們可以進行狀態轉移,以及模板匹配。要求目標串長度為n,且包含k個給定字串。所以可以在包含給定字串的ac自動機上進行狀態轉移。dp i 1 u last u s dp i 1 u last u s dp i j s mod...
HDU 6086 AC自動機 狀壓dp
給出m個單詞,要構造出長度為2 l的包含這全部m個單詞的字串,並且保證這個字串非對稱,其中字元只包括0和1,問一共有多少種構造方法。在2825的基礎上,本題增加了非對稱的性質,很顯然,只要確定了一半,另一半就固定了。比賽的時候想到了只構造右半邊,要將子串列舉斷點對折來看,但是當時想的是從中間到兩邊的...