ACM演算法模板 · 一些常用的演算法模板-模板合集(打比賽專用)
阿新 • • 發佈:2019-02-02
0.標頭檔案
#define _CRT_SBCURE_NO_DEPRECATE
#include <set>
#include <cmath>
#include <queue>
#include <stack>
#include <vector>
#include <string>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <functional>
using namespace std;
const int maxn = 110;
const int INF = 0x3f3f3f3f;
經典
1.埃拉託斯特尼篩法
/*
|埃式篩法|
|快速篩選素數|
|16/11/05ztx|
*/
int prime[maxn];
bool is_prime[maxn];
int sieve(int n){
int p = 0;
for(int i = 0; i <= n; ++i)
is_prime[i] = true;
is_prime[0 ] = is_prime[1] = false;
for (int i = 2; i <= n; ++i){ // 注意陣列大小是n
if(is_prime[i]){
prime[p++] = i;
for(int j = i + i; j <= n; j += i) // 輕剪枝,j必定是i的倍數
is_prime[j] = false;
}
}
return p; // 返回素數個數
}
2.快速冪
/*
|快速冪|
|16/11/05ztx|
*/
typedef long long LL; // 視資料大小的情況而定
LL powerMod(LL x, LL n, LL m)
{
LL res = 1;
while (n > 0){
if (n & 1) // 判斷是否為奇數,若是則true
res = (res * x) % m;
x = (x * x) % m;
n >>= 1; // 相當於n /= 2;
}
return res;
}
3.大數模擬
大數加法
/*
|大數模擬加法|
|用string模擬|
|16/11/05ztx, thanks to caojiji|
*/
string add1(string s1, string s2)
{
if (s1 == "" && s2 == "") return "0";
if (s1 == "") return s2;
if (s2 == "") return s1;
string maxx = s1, minn = s2;
if (s1.length() < s2.length()){
maxx = s2;
minn = s1;
}
int a = maxx.length() - 1, b = minn.length() - 1;
for (int i = b; i >= 0; --i){
maxx[a--] += minn[i] - '0'; // a一直在減 , 額外還要減個'0'
}
for (int i = maxx.length()-1; i > 0;--i){
if (maxx[i] > '9'){
maxx[i] -= 10;//注意這個是減10
maxx[i - 1]++;
}
}
if (maxx[0] > '9'){
maxx[0] -= 10;
maxx = '1' + maxx;
}
return maxx;
}
大數階乘
/*
|大數模擬階乘|
|用陣列模擬|
|16/12/02ztx|
*/
#include <iostream>
#include <cstdio>
using namespace std;
typedef long long LL;
const int maxn = 100010;
int num[maxn], len;
/*
在mult函式中,形參部分:len每次呼叫函式都會發生改變,n表示每次要乘以的數,最終返回的是結果的長度
tip: 階乘都是先求之前的(n-1)!來求n!
初始化Init函式很重要,不要落下
*/
void Init() {
len = 1;
num[0] = 1;
}
int mult(int num[], int len, int n) {
LL tmp = 0;
for(LL i = 0; i < len; ++i) {
tmp = tmp + num[i] * n; //從最低位開始,等號左邊的tmp表示當前位,右邊的tmp表示進位(之前進的位)
num[i] = tmp % 10; // 儲存在對應的陣列位置,即去掉進位後的一位數
tmp = tmp / 10; // 取整用於再次迴圈,與n和下一個位置的乘積相加
}
while(tmp) { // 之後的進位處理
num[len++] = tmp % 10;
tmp = tmp / 10;
}
return len;
}
int main() {
Init();
int n;
n = 1977; // 求的階乘數
for(int i = 2; i <= n; ++i) {
len = mult(num, len, i);
}
for(int i = len - 1; i >= 0; --i)
printf("%d",num[i]); // 從最高位依次輸出,資料比較多采用printf輸出
printf("\n");
return 0;
}
4.GCD
/*
|輾轉相除法|
|歐幾里得演算法|
|求最大公約數|
|16/11/05ztx|
*/
int gcd(int big, int small)
{
if (small > big) swap(big, small);
int temp;
while (small != 0){ // 輾轉相除法
if (small > big) swap(big, small);
temp = big % small;
big = small;
small = temp;
}
return(big);
}
5.LCM
/*
|輾轉相除法|
|歐幾里得演算法|
|求最小公倍數|
|16/11/05ztx|
*/
int gcd(int big, int small)
{
if (small > big) swap(big, small);
int temp;
while (small != 0){ // 輾轉相除法
if (small > big) swap(big, small);
temp = big % small;
big = small;
small = temp;
}
return(big);
}
6.全排列
/*
|求1到n的全排列, 有條件|
|16/11/05ztx, thanks to wangqiqi|
*/
void Pern(int list[], int k, int n) { // k表示前k個數不動僅移動後面n-k位數
if (k == n - 1) {
for (int i = 0; i < n; i++) {
printf("%d", list[i]);
}
printf("\n");
}else {
for (int i = k; i < n; i++) { // 輸出的是滿足移動條件所有全排列
swap(list[k], list[i]);
Pern(list, k + 1, n);
swap(list[k], list[i]);
}
}
}
7.二分搜尋
/*
|二分搜尋|
|要求:先排序|
|16/11/05ztx, thanks to wangxiaocai|
*/
// left為最開始元素, right是末尾元素的下一個數,x是要找的數
int bsearch(int *A, int left, int right, int x){
int m;
while (left < right){
m = left + (right - left) / 2;
if (A[m] >= x) right = m; else left = m + 1;
// 如果要替換為 upper_bound, 改為:if (A[m] <= v) x = m+1; else y = m;
}
return left;
}
/*
最後left == right
如果沒有找到135577找6,返回7
如果找有多少的x,可以用lower_bound查詢一遍,upper_bound查詢一遍,下標相減
C++自帶的lower_bound(a,a+n,x)返回陣列中最後一個x的下一個數的地址
upper_bound(a,a+n,x)返回陣列中第一個x的地址
如果a+n內沒有找到x或x的下一個地址,返回a+n的地址
lower_bound(a,a+n,x)-upper_bound(a,a+n,x)返回陣列中x的個數
*/
資料結構
並查集
8.並查集
/*
|合併節點操作|
|16/11/05ztx, thanks to chaixiaojun|
*/
int father[maxn]; // 儲存i的father父節點
void makeSet() {
for (int i = 0; i < maxn; i++)
father[i] = i;
}
int findRoot(int x) { // 迭代找根節點
int root = x; // 根節點
while (root != father[root]) { // 尋找根節點
root = father[root];
}
while (x != root) {
int tmp = father[x];
father[x] = root; // 根節點賦值
x = tmp;
}
return root;
}
void Union(int x, int y) { // 將x所在的集合和y所在的集合整合起來形成一個集合。
int a, b;
a = findRoot(x);
b = findRoot(y);
father[a] = b; // y連在x的根節點上 或father[b] = a為x連在y的根節點上;
}
/*
在findRoot(x)中:
路徑壓縮 迭代 最優版
關鍵在於在路徑上的每個節點都可以直接連線到根上
*/
圖論
MST
最小生成樹
Kruskal
9.克魯斯卡爾演算法
/*
|Kruskal演算法|
|適用於 稀疏圖 求最小生成樹|
|16/11/05ztx thanks to wangqiqi|
*/
/*
第一步:點、邊、加入vector,把所有邊按從小到大排序
第二步:並查集部分 + 下面的code
*/
void Kruskal() {
ans = 0;
for (int i = 0; i<len; i++) {
if (Find(edge[i].a) != Find(edge[i].b)) {
Union(edge[i].a, edge[i].b);
ans += edge[i].len;
}
}
}
Prim
10.普里姆演算法
/*
|Prim演算法|
|適用於 稠密圖 求最小生成樹|
|堆優化版,時間複雜度:O(elgn)|
|16/11/05ztx, thanks to chaixiaojun|
*/
struct node {
int v, len;
node(int v = 0, int len = 0) :v(v), len(len) {}
bool operator < (const node &a)const { // 加入佇列的元素自動按距離從小到大排序
return len> a.len;
}
};
vector<node> G[maxn];
int vis[maxn];
int dis[maxn];
void init() {
for (int i = 0; i<maxn; i++) {
G[i].clear();
dis[i] = INF;
vis[i] = false;
}
}
int Prim(int s) {
priority_queue<node>Q; // 定義優先佇列
int ans = 0;
Q.push(node(s,0)); // 起點加入佇列
while (!Q.empty()) {
node now = Q.top(); Q.pop(); // 取出距離最小的點
int v = now.v;
if (vis[v]) continue; // 同一個節點,可能會推入2次或2次以上佇列,這樣第一個被標記後,剩下的需要直接跳過。
vis[v] = true; // 標記一下
ans += now.len;
for (int i = 0; i<G[v].size(); i++) { // 開始更新
int v2 = G[v][i].v;
int len = G[v][i].len;
if (!vis[v2] && dis[v2] > len) {
dis[v2] = len;
Q.push(node(v2, dis[v2])); // 更新的點加入佇列並排序
}
}
}
return ans;
}
Bellman-Ford
單源最短路
Dijkstra
11.迪傑斯特拉演算法
/*
|Dijkstra演算法|
|適用於邊權為正的有向圖或者無向圖|
|求從單個源點出發,到所有節點的最短路|
|優化版:時間複雜度 O(elbn)|
|16/11/05ztx, thanks to chaixiaojun|
*/
struct node {
int v, len;
node(int v = 0, int len = 0) :v(v), len(len) {}
bool operator < (const node &a)const { // 距離從小到大排序
return len > a.len;
}
};
vector<node>G[maxn];
bool vis[maxn];
int dis[maxn];
void init() {
for (int i = 0; i<maxn; i++) {
G[i].clear();
vis[i] = false;
dis[i] = INF;
}
}
int dijkstra(int s, int e) {
priority_queue<node>Q;
Q.push(node(s, 0)); // 加入佇列並排序
dis[s] = 0;
while (!Q.empty()) {
node now = Q.top(); // 取出當前最小的
Q.pop();
int v = now.v;
if (vis[v]) continue; // 如果標記過了, 直接continue
vis[v] = true;
for (int i = 0; i<G[v].size(); i++) { // 更新
int v2 = G[v][i].v;
int len = G[v][i].len;
if (!vis[v2] && dis[v2] > dis[v] + len) {
dis[v2] = dis[v] + len;
Q.push(node(v2, dis[v2]));
}
}
}
return dis[e];
}
SPFA
12.最短路徑快速演算法(Shortest Path Faster Algorithm)
/*
|SPFA演算法|
|佇列優化|
|可處理負環|
*/
vector<node> G[maxn];
bool inqueue[maxn];
int dist[maxn];
void Init()
{
for(int i = 0 ; i < maxn ; ++i){
G[i].clear();
dist[i] = INF;
}
}
int SPFA(int s,int e)
{
int v1,v2,weight;
queue<int> Q;
memset(inqueue,false,sizeof(inqueue)); // 標記是否在佇列中
memset(cnt,0,sizeof(cnt)); // 加入佇列的次數
dist[s] = 0;
Q.push(s); // 起點加入佇列
inqueue[s] = true; // 標記
while(!Q.empty()){
v1 = Q.front();
Q.pop();
inqueue[v1] = false; // 取消標記
for(int i = 0 ; i < G[v1].size() ; ++i){ // 搜尋v1的連結串列
v2 = G[v1][i].vex;
weight = G[v1][i].weight;
if(dist[v2] > dist[v1] + weight){ // 鬆弛操作
dist[v2] = dist[v1] + weight;
if(inqueue[v2] == false){ // 再次加入佇列
inqueue[v2] = true;
//cnt[v2]++; // 判負環
//if(cnt[v2] > n) return -1;
Q.push(v2);
} } }
}
return dist[e];
}
/*
不斷的將s的鄰接點加入佇列,取出不斷的進行鬆弛操作,直到佇列為空
如果一個結點被加入佇列超過n-1次,那麼顯然圖中有負環
*/
Floyd-Warshall
13.弗洛伊德演算法
/*
|Floyd演算法|
|任意點對最短路演算法|
|求圖中任意兩點的最短距離的演算法|
*/
for (int i = 0; i < n; i++) { // 初始化為0
for (int j = 0; j < n; j++)
scanf("%lf", &dis[i][j]);
}
for (int k = 0; k < n; k++) {
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
dis[i][j] = min(dis[i][j], dis[i][k] + dis[k][j]);
}
}
}
二分圖
14.染色法
/*
|交叉染色法判斷二分圖|
|16/11/05ztx|
*/
int bipartite(int s) {
int u, v;
queue<int>Q;
color[s] = 1;
Q.push(s);
while (!Q.empty()) {
u = Q.front();
Q.pop();
for (int i = 0; i < G[u].size(); i++) {
v = G[u][i];
if (color[v] == 0) {
color[v] = -color[u];
Q.push(v);
}
else if (color[v] == color[u])
return 0;
}
}
return 1;
}
15..匈牙利演算法
/*
|求解最大匹配問題|
|遞迴實現|
|16/11/05ztx|
*/
vector<int>G[maxn];
bool inpath[maxn]; // 標記
int match[maxn]; // 記錄匹配物件
void init()
{
memset(match, -1, sizeof(match));
for (int i = 0; i < maxn; ++i) {
G[i].clear();
}
}
bool findpath(int k) {
for (int i = 0; i < G[k].size(); ++i) {
int v = G[k][i];
if (!inpath[v]) {
inpath[v] = true;
if (match[v] == -1 || findpath(match[v])) { // 遞迴
match[v] = k; // 即匹配物件是“k妹子”的
return true;
}
}
}
return false;
}
void hungary() {
int cnt = 0;
for (int i = 1; i <= m; i++) { // m為需要匹配的“妹子”數
memset(inpath, false, sizeof(inpath)); // 每次都要初始化
if (findpath(i)) cnt++;
}
cout << cnt << endl;
}
/*
|求解最大匹配問題|
|dfs實現|
|16/11/05ztx|
*/
int v1, v2;
bool Map[501][501];
bool visit[501];
int link[501];
int result;
bool dfs(int x) {
for (int y = 1; y <= v2; ++y) {
if (Map[x][y] && !visit[y]) {
visit[y] = true;
if (link[y] == 0 || dfs(link[y])) {
link[y] = x;
return true;
} } }
return false;
}
void Search() {
for (int x = 1; x <= v1; x++) {
memset(visit,false,sizeof(visit));
if (dfs(x))
result++;
}
}
動態規劃
揹包
16.17.18揹包問題
/*
|01揹包|
|完全揹包|
|多重揹包|
|16/11/05ztx|
*/
// 01揹包:
void bag01(int cost,int weight) {
for(i = v; i >= cost; --i)
dp[i] = max(dp[i], dp[i-cost]+weight);
}
// 完全揹包:
void complete(int cost, int weight) {
for(i = cost ; i <= v; ++i)
dp[i] = max(dp[i], dp[i - cost] + weight);
}
// 多重揹包:
void multiply(int cost, int weight, int amount) {
if(cost * amount >= v)
complete(cost, weight);
else{
k = 1;
while (k < amount){
bag01(k * cost, k * weight);
amount -= k;
k += k;
}
bag01(cost * amount, weight * amount);
}
}
// other
int dp[1000000];
int c[55], m[110];
int sum;
void CompletePack(int c) {
for (int v = c; v <= sum / 2; ++v){
dp[v] = max(dp[v], dp[v - c] + c);
}
}
void ZeroOnePack(int c) {
for (int v = sum / 2; v >= c; --v) {
dp[v] = max(dp[v], dp[v - c] + c);
}
}
void multiplePack(int c, int m) {
if (m * c > sum / 2)
CompletePack(c);
else{
int k = 1;
while (k < m){
ZeroOnePack(k * c);
m -= k;
k <<= 1;
}
if (m != 0){
ZeroOnePack(m * c);
}
}
}
LIS
19.最長上升子序列
/*
|最長上升子序列|
|狀態轉移|
|16/11/05ztx|
*/
/*
狀態轉移dp[i] = max{ 1.dp[j] + 1 }; j<i; a[j]<a[i];
d[i]是以i結尾的最長上升子序列
與i之前的 每個a[j]<a[i]的 j的位置的最長上升子序列+1後的值比較
*/
void solve(){ // 參考挑戰程式設計入門經典;
for(int i = 0; i < n; ++i){
dp[i] = 1;
for(int j = 0; j < i; ++j){
if(a[j] < a[i]){
dp[i] = max(dp[i], dp[j] + 1);
} } }
}
/*
優化方法:
dp[i]表示長度為i+1的上升子序列的最末尾元素
找到第一個比dp末尾大的來代替
*/
void solve() {
for (int i = 0; i < n; ++i){
dp[i] = INF;
}
for (int i = 0; i < n; ++i) {
*lower_bound(dp, dp + n, a[i]) = a[i]; // 返回一個指標
}
printf("%d\n", *lower_bound(dp, dp + n, INF) - dp;
}
/*
函式lower_bound()返回一個 iterator 它指向在[first,last)標記的有序序列中可以插入value,而不會破壞容器順序的第一個位置,而這個位置標記了一個不小於value的值。
*/
LCS
20.最長公共子序列
/*
|求最長公共子序列|
|遞推形式|
|16/11/05ztx|
*/
void solve() {
for (int i = 0; i < n; ++i) {
for (int j = 0; j < m; ++j) {
if (s1[i] == s2[j]) {
dp[i + 1][j + 1] = dp[i][j] + 1;
}else {
dp[i + 1][j + 1] = max(dp[i][j + 1], dp[i + 1][j]);
} } }
}
計算幾何
21.向量基本用法
/*
|16/11/06ztx|
*/
struct node {
double x; // 橫座標
double y; // 縱座標
};
typedef node Vector;
Vector operator + (Vector A, Vector B) { return Vector(A.x + B.x, A.y + B.y); }
Vector operator - (Point A, Point B) { return Vector(A.x - B.y, A.y - B.y); }
Vector operator * (Vector A, double p) { return Vector(A.x*p, A.y*p); }
Vector operator / (Vector A, double p) { return Vector(A.x / p, A.y*p); }
double Dot(Vector A, Vector B) { return A.x*B.x + A.y*B.y; } // 向量點乘
double Length(Vector A) { return sqrt(Dot(A, A)); } // 向量模長
double Angle(Vector A, Vector B) { return acos(Dot(A, B) / Length(A) / Length(B)); } // 向量之間夾角
double Cross(Vector A, Vector B) { // 叉積計算 公式
return A.x*B.y - A.y*B.x;
}
Vector Rotate(Vector A, double rad) // 向量旋轉 公式 {
return Vector(A.x*cos(rad) - A.y*sin(rad), A.x*sin(rad) + A.y*cos(rad));
}
Point getLineIntersection(Point P, Vector v, Point Q, Vector w) { // 兩直線交點t1 t2計算公式
Vector u = P - Q;
double t = Cross(w, u) / Cross(v, w); // 求得是橫座標
return P + v*t; // 返回一個點
}
22.求多邊形面積
/*
|16/11/06ztx|
*/
node G[maxn];
int n;
double Cross(node a, node b) { // 叉積計算
return a.x*b.y - a.y*b.x;
}
int main()
{
while (scanf("%d", &n) != EOF && n) {
for (int i = 0; i < n; i++)
scanf("%lf %lf", &G[i].x, &G[i].y);
double sum = 0;
G[n].x = G[0].x;
G[n].y = G[0].y;
for (int i = 0; i < n; i++) {
sum += Cross(G[i], G[i + 1]);
}
// 或者
//for (int i = 0; i < n; i++) {
//sum += fun(G[i], G[(i + 1)% n]);
//}
sum = sum / 2.0;
printf("%.1f\n", sum);
}
system("pause");
return 0;
}
23..判斷線段相交
/*
|16/11/06ztx|
*/
node P[35][105];
double Cross_Prouct(node A,node B,node C) { // 計算BA叉乘CA
return (B.x-A.x)*(C.y-A.y)-(B.y-A.y)*(C.x-A.x);
}
bool Intersect(node A,node B,node C,node D) { // 通過叉乘判斷線段是否相交;
if(min(A.x,B.x)<=max(C.x,D.x)&& // 快速排斥實驗;
min(C.x,D.x)<=max(A.x,B.x)&&
min(A.y,B.y)<=max(C.y,D.y)&&
min(C.y,D.y)<=max(A.y,B.y)&&
Cross_Prouct(A,B,C)*Cross_Prouct(A,B,D)<0&& // 跨立實驗;
Cross_Prouct(C,D,A)*Cross_Prouct(C,D,B)<0) // 叉乘異號表示在兩側;
return true;
else return false;
}
24.求三角形外心
/*
|16/11/06ztx|
*/
Point circumcenter(const Point &a, const Point &b, const Point &c) { //返回三角形的外心
Point ret;
double a1 = b.x - a.x, b1 = b.y - a.y, c1 = (a1*a1 + b1*b1) / 2;
double a2 = c.x - a.x, b2 = c.y - a.y, c2 = (a2*a2 + b2*b2) / 2;
double d = a1*b2 - a2*b1;
ret.x = a.x + (c1*b2 - c2*b1) / d;
ret.y = a.y + (a1*c2 - a2*c1) / d;
return ret;
}
24.極角排序
/*
|16/11/06ztx|
*/
double cross(point p1, point p2, point q1, point q2) { // 叉積計算
return (q2.y - q1.y)*(p2.x - p1.x) - (q2.x - q1.x)*(p2.y - p1.y);
}
bool cmp(point a, point b) {
point o;
o.x = o.y = 0;
return cross(o, b, o, a) < 0; // 叉積判斷
}
sort(convex + 1, convex + cnt, cmp); // 按角排序, 從小到大
字串
kmp
25.克努特-莫里斯-普拉特操作
/*
|kmp演算法|
|字串匹配|
|17/1/21ztx|
*/
void getnext(char str[maxn], int nextt[maxn]) {
int j = 0, k = -1;
nextt[0] = -1;
while (j < m) {
if (k == -1 || str[j] == str[k]) {
j++;
k++;
nextt[j] = k;
}
else
k = nextt[k];
}
}
void kmp(int a[maxn], int b[maxn]) {
int nextt[maxm];
int i = 0, j = 0;
getnext(b, nextt);
while (i < n) {
if (j == -1 || a[i] == b[j]) { // 母串不動,子串移動
j++;
i++;
}
else {
// i不需要回溯了
// i = i - j + 1;
j = nextt[j];
}
if (j == m) {
printf("%d\n", i - m + 1); // 母串的位置減去子串的長度+1
return;
}
}
printf("-1\n");
}
26.kmp擴充套件
/*
|16/11/06ztx|
*/
#include<iostream>
#include<cstring>
using namespace std;
const int MM=100005;
int next[MM],extand[MM];
char S[MM],T[MM];
void GetNext(const char *T) {
int len = strlen(T),a = 0;
next[0] = len;
while(a < len - 1 && T[a] == T[a + 1]) a++;
next[1] = a;
a = 1;
for(int k = 2; k < len; k ++) {
int p = a + next[a] - 1,L = next[k - a];
if( (k - 1) + L >= p) {
int j = (p - k + 1) > 0 ? (p - k + 1) : 0;
while(k + j < len && T[k + j] == T[j]) j++;
next[k] = j;
a = k;
}else next[k] = L;
}
}
void GetExtand(const char *S,const char *T) {
GetNext(T);
int slen = strlen(S),tlen = strlen(T),a = 0;
int MinLen = slen < tlen ? slen : tlen;
while(a < MinLen && S[a] == T[a]) a++;
extand[0] = a;
a = 0;
for(int k = 1; k < slen; k ++) {
int p = a + extand[a] - 1, L = next[k - a];
if( (k - 1) + L >= p) {
int j = (p - k + 1) > 0 ? (p - k + 1) : 0;
while(k + j < slen && j < tlen && S[k + j] == T[j]) j ++;
extand[k] = j;
a = k;
} else
extand[k] = L;
}
}
void show(const int *s,int len){
for(int i = 0; i < len; i ++)
cout << s[i] << ' ';
cout << endl;
}
int main() {
while(cin >> S >> T) {
GetExtand(S,T);
show(next,strlen(T));
show(extand,strlen(S));
}
return 0;
}
字典樹
27.字典樹
/*
|16/11/06ztx|
*/
struct Trie{
int cnt;
Trie *next[maxn];
Trie(){
cnt = 0;
memset(next,0,sizeof(next));
}
};
Trie *root;
void Insert(char *word) {
Trie *tem = root;
while(*word != '\0') {
int x = *word - 'a';
if(tem->next[x] == NULL)
tem->next[x] = new Trie;
tem = tem->next[x];
tem->cnt++;
word++;
}
}
int Search(char *word) {
Trie *tem = root;
for(int i=0;word[i]!='\0';i++) {
int x = word[i]-'a';
if(tem->next[x] == NULL)
return 0;
tem = tem->next[x];
}
return tem->cnt;
}
void Delete(char *word,int t) {
Trie *tem = root;
for(int i=0;word[i]!='\0';i++) {
int x = word[i]-'a';
tem = tem->next[x];
(tem->cnt)-=t;
}
for(int i=0;i<maxn;i++)
tem->next[i] = NULL;
}
int main() {
int n;
char str1[50];
char str2[50];
while(scanf("%d",&n)!=EOF) {
root = new Trie;
while(n--) {
scanf("%s %s",str1,str2);
if(str1[0]=='i') {
Insert(str2);
}else if(str1[0] == 's') {
if(Search(str2))
printf("Yes\n");
else
printf("No\n");
}else {
int t = Search(str2);
if(t)
Delete(str2,t);
} } }
return 0;
}
28.AC自動機
/*
|16/11/06ztx|
*/
#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
using namespace std;
#define N 1000010
char str[N], keyword[N];
int head, tail;
struct node {
node *fail;
node *next[26];
int count;
node() { //init
fail = NULL;// 預設為空
count = 0;
for(int i = 0; i < 26; ++i)
next[i] = NULL;
}
}*q[N];
node *root;
void insert(char *str) { // 建立Trie
int temp, len;
node *p = root;
len = strlen(str);
for(int i = 0; i < len; ++i) {
temp = str[i] - 'a';
if(p->next[temp] == NULL)
p->next[temp] = new node();
p = p->next[temp];
}
p->count++;
}
void build_ac() { // 初始化fail指標,BFS 陣列模擬佇列:
q[tail++] = root;
while(head != tail) {
node *p = q[head++]; // 彈出隊頭
node *temp = NULL;
for(int i = 0; i < 26; ++i) {
if(p->next[i] != NULL) {
if(p == root) { // 第一個元素fail必指向根
p->next[i]->fail = root;
}else {
temp = p->fail; // 失敗指標
while(temp != NULL) { // 2種情況結束:匹配為空or找到匹配
if(temp->next[i] != NULL) { // 找到匹配
p->next[i]->fail = temp->next[i];
break;