zoukankan      html  css  js  c++  java
  • KMP算法题集

    模板

    caioj 1177 KMP模板

    #include<bits/stdc++.h>
    #define REP(i, a, b) for(register int i = (a); i < (b); i++)
    #define _for(i, a, b) for(register int i = (a); i <= (b); i++)
    using namespace std;
    
    const int MAXN = 1e6 + 10;
    const int MAXM = 1e3 + 10;
    char a[MAXN], b[MAXM]; 
    int next[MAXM], lena, lenb; 
    
    void get_next()
    {
    	next[1] = 0; int j = 0;
    	_for(i, 2, lenb)
    	{
    		while(j > 0 && b[j + 1] != b[i]) j = next[j];
    		if(b[j + 1] == b[i]) j++;
    		next[i] = j;	
    	} 
    }
    
    void kmp()
    {
    	int j = 0;
    	_for(i, 1, lena)
    	{
    		while(j > 0 && (j == lenb || b[j + 1] != a[i]))  j = next[j]; 
    		if(b[j + 1] == a[i]) j++;
    		if(j == lenb) { printf("%d %d
    ", i - lenb + 1, i); return; }	
    	}
    	puts("NO");
    }
    
    int main()
    {
    	scanf("%s%s", a + 1, b + 1);
    	lena = strlen(a + 1); lenb = strlen(b + 1);
    	get_next();
    	kmp();
    	return 0;
    }

    caioj 1460: 【KMP】字符串匹配

    #include<bits/stdc++.h>
    #define REP(i, a, b) for(register int i = (a); i < (b); i++)
    #define _for(i, a, b) for(register int i = (a); i <= (b); i++)
    using namespace std;
    
    const int MAXN = 1e6 + 10;
    char a[MAXN], b[MAXN]; 
    int next[MAXN], lena, lenb;
    
    void get_next()
    {
    	next[1] = 0; int j = 0;
    	_for(i, 2, lena)
    	{
    		while(j > 0 && a[j + 1] != a[i]) j = next[j];
    		if(a[j + 1] == a[i]) j++;
    		next[i] = j;
    	}
    }
    
    int kmp()
    {
    	int res = 0, j = 0;
    	_for(i, 1, lenb)
    	{
    		while(j > 0 && a[j + 1] != b[i]) j = next[j];
    		if(a[j + 1] == b[i]) j++;
    		if(j == lena) { res++; j = next[j]; }	
    	}	
    	return res;
    } 
    
    int main()
    {
    	int T;
    	scanf("%d", &T);
    	while(T--)
    	{
    		scanf("%s%s", a + 1, b + 1);
    		lena = strlen(a + 1); lenb = strlen(b + 1); 
    		get_next();
    		printf("%d
    ", kmp());
    	}
    	return 0;
    }

    重复子串结论

    有一个结论。

    对于字符串S[1~i],如果i % (i - next[i]) == 0,那么这个字符串就由很多个重复的子串构成(形如abababab)

    每个循环节等于S[1~i-next[i]],循环节的个数为i / (i - next[i])

    这个结论很好证明,用笔画一下就可以发现这个性质

    caioj 1457: 【KMP】重复的子串

    #include<bits/stdc++.h>
    #define REP(i, a, b) for(register int i = (a); i < (b); i++)
    #define _for(i, a, b) for(register int i = (a); i <= (b); i++)
    using namespace std;
    
    const int MAXN = 1e6 + 10;
    char a[MAXN]; 
    int next[MAXN], lena; 
    
    void get_next()
    {
    	next[1] = 0; int j = 0;
    	_for(i, 2, lena)
    	{
    		while(j > 0 && a[j + 1] != a[i]) j = next[j];
    		if(a[j + 1] == a[i]) j++;
    		next[i] = j;	
    	} 
    }
    
    int main()
    {
    	while(scanf("%s", a + 1))
    	{
    		if(a[1] == '.') break;
    		lena = strlen(a + 1);
    		get_next();
    		if(lena % (lena - next[lena]) == 0) 
    			printf("%d
    ", lena / (lena - next[lena]));
    		else puts("1");
    	}
    	return 0;
    }

    caioj 1458: 【KMP】判断循环段位置

    #include<bits/stdc++.h>
    #define REP(i, a, b) for(register int i = (a); i < (b); i++)
    #define _for(i, a, b) for(register int i = (a); i <= (b); i++)
    using namespace std;
    
    const int MAXN = 1e6 + 10;
    char a[MAXN]; 
    int next[MAXN], lena; 
    
    void get_next()
    {
    	next[1] = 0; int j = 0;
    	_for(i, 2, lena)
    	{
    		while(j > 0 && a[j + 1] != a[i]) j = next[j];
    		if(a[j + 1] == a[i]) j++;
    		next[i] = j;	
    	} 
    }
    
    int main()
    {
    	scanf("%s", a + 1);
    	lena = strlen(a + 1);
    	get_next();
    	_for(i, 2, lena)
    		if(i % (i - next[i]) == 0 && i / (i - next[i]) > 1)
    			printf("%d %d
    ", i, i / (i - next[i]));
    	return 0;
    }

    next数组应用

    caioj 1459: 【KMP】所有前缀等于后缀的情况

    #include<bits/stdc++.h>
    #define REP(i, a, b) for(register int i = (a); i < (b); i++)
    #define _for(i, a, b) for(register int i = (a); i <= (b); i++)
    using namespace std;
    
    const int MAXN = 1e6 + 10;
    char a[MAXN]; 
    int next[MAXN], lena; 
    
    void get_next()
    {
    	next[1] = 0; int j = 0;
    	_for(i, 2, lena)
    	{
    		while(j > 0 && a[j + 1] != a[i]) j = next[j];
    		if(a[j + 1] == a[i]) j++;
    		next[i] = j;	
    	} 
    }
    
    int main()
    {
    	while(~scanf("%s", a + 1))
    	{
    		lena = strlen(a + 1);
    		get_next();
    		int j = lena;
    		stack<int> s;
    		while(j) s.push(j), j = next[j];
    		while(!s.empty()) printf("%d ", s.top()), s.pop();
    		puts("");
    	}
    	return 0;
    }

    综合题

    poj 2185

    这道题不知道为什么一直A不了。先放着

    #include<cstdio>
    #include<queue>
    #include<cstring> 
    #include<algorithm> 
    #define REP(i, a, b) for(register int i = (a); i < (b); i++)
    #define _for(i, a, b) for(register int i = (a); i <= (b); i++)
    using namespace std;
    
    const int MAXN = 1e4 + 10;
    const int MAXM = 75 + 10;
    char s[MAXN][MAXM], t[MAXN];
    int next[MAXN], f[MAXN];
    int n, m, r, c, j;
    
    int get_r() //一行看作一个字符,很牛逼。 
    {
    	next[1] = 0;
    	for(int i = 2, j = 0; i <= n; i++)
    	{
    		if(j > 0 && strcmp(s[j + 1], s[i])) j = next[j];
    		if(!strcmp(s[j + 1], s[i])) j++;
    		next[i] = j;
    	}
    	return n - next[n];
    }
    
    int get_c()
    {
    	memset(f, 0, sizeof(f));
    	_for(i, 1, n)
    		_for(len, 1, m)
    			REP(j, 0, m)
    			{
    				if(s[i][j] != s[i][j % len]) break; //这个操作要学学 
    				if(j == m - 1) f[len]++;
    			}	
    	_for(i, 1, m) //用桶这个思路很妙 
    		if(f[i] == n)
    			return i;
    }
    
    int main()
    {
    	scanf("%d%d", &n, &m); 
    	_for(i, 1, n) scanf("%s", s[i]);
    	printf("%d
    ", get_r() * get_c());
    	return 0;
    }
  • 相关阅读:
    BZOJ4327 : JSOI2012 玄武密码
    BZOJ4303 : 数列
    BZOJ1077 : [SCOI2008]天平
    BZOJ1829 : [Usaco2010 Mar]starc星际争霸
    BZOJ1770 : [Usaco2009 Nov]lights 燈
    BZOJ3012 : [Usaco2012 Dec]First!
    BZOJ4320 : ShangHai2006 Homework
    BZOJ4311 : 向量
    BZOJ3075 : [Usaco2013]Necklace
    BZOJ4304 : 道路改建
  • 原文地址:https://www.cnblogs.com/sugewud/p/9819310.html
Copyright © 2011-2022 走看看