自动状态机
图灵机大概就是一个“自动机”,就是说代码分好几种状态,每种状态做不同的事。
举个简单的例子吧
输入一个字符串,输入的只有两种字符,一种是字母,一种是空格。现在求一共有几个单词。注意,有可能有多个空格连在一起,开头和结尾都有可能有空格。
那么这是一道简单的有穷自动机,运行时分两种情况:
①是空格
②是字母
(其实当前状态就是上一个字符的状态
那么在遍历数组的时候拿一个变量记录下来当前是什么状态,可以用0代表当前是空格状态,1代表是字母状态
当如果当前状态是1,而现在却遇到空格,那么就计数器加一,同时要将状态改为0,如果当前状态是0,现在的字符却是字母,就只将状态改为1
BUT!
在跳出循环的时候如果状态是1,要将计数器加一,否则如果最后是字母就会少统计一个单词!(想想为什么)
状态图:
#include<bits/stdc++.h> //万能头文件
using namespace std;
int main () {
char a[1001];
int state, ans = 0;
//0表示空格,1表示字母
gets(a);
if (a[0] == ' ') {
//设置初始值
state = 0;
} else {
//表示字母
state = 1;
}
for (int i = 1; a[i]; i++) {
//是空格
if (a[i] == ' ') {
//判断当前状态(前一个)是字母,说明找到一个单词了
if (state == 1) {
//答案加一
ans++;
//改状态
state = 0;
}
} else { //是字母
if (state == 0) { //当前状态(前一个)是空格
state = 1; //将状态改为1
}
}
}
//最后还要判断一下千万不要忘记
if (state == 1) {
ans++;
}
cout<<ans;
}
引入题目:统计单词数
题目描述
一般的文本编辑器都有查找单词的功能,该功能可以快速定位特定单词在文章中的位置,有的还能统计出特定单词在文章中出现的次数。
现在,请你编程实现这一功能,具体要求是:给定一个单词,请你输出它在给定的文章中出现的次数和第一次出现的位置。注意:匹配单词时,不区分大小写,但要求完全匹配,即给定单词必须与文章中的某一独立单词在不区分大小写的情况下完全相同(参见样例1 ),如果给定单词仅是文章中某一单词的一部分则不算匹配(参见样例2 )。
输入格式
共2行。
第1行为一个字符串,其中只含字母,表示给定单词;
第2行为一个字符串,其中只可能包含字母和空格,表示给定的文章。
输出格式
一行,如果在文章中找到给定单词则输出两个整数,两个整数之间用一个空格隔开,分别是单词在文章中出现的次数和第一次出现的位置(即在文章中第一次出现时,单词首字母在文章中的位置,位置从0 开始);如果单词在文章中没有出现,则直接输出一个整数-1。
输入输出样例
输入 #1
To
to be or not to be is a question
输出 #1
2 0
输入 #2
to
Did the Ottoman Empire lose its power at that time
输出 #2
-1
说明/提示
数据范围
1≤单词长度≤10。
1≤文章长度≤1,000,000。
noip2011普及组第2题
那么,这就是简单的自动机代码,现在看看本题用自动机如何做
其实一样,就是注意字母状态分时要查找单词状态和不是要查找单词状态,而且单词第n个字母的状态就用n来表示
以下是code:
#include<bits/stdc++.h> //万能头文件
using namespace std;
//其实一样,就是注意字母状态分为 要查找单词状态和不是要查找单词状态,
// 而且单词第n个字母的状态就用n来表示
const int SPACE = 0; // 三种状态,这是空格状态
const int LETTER = -1; // 字母状态,但这表示不是要查找的单词的字母的状态
const int WORD = 1; // 而这种状态是要查找的单词的状态
//当然了,如果状态是大于1的数,说明是要查找的单词的中间部分的状态,
inline void strlower (char *a) {//不解释,上面的代码有了
for(int i = 0; a[i]; i ++ ) {
if(isupper(a[i])) a[i] = tolower(a[i]);
}
}
int main () {
char a[1000001], word[20];
int ans = 0;
int ans2 = -1;
int state = 0;//表状态,假设是空格,因为空格上来就判断是不是三种状态
int i;
gets(word);
gets(a);
strlower(a);
strlower(word);
int len = strlen(word);
for (i = 0; a[i]; i++) { //遍历数组
switch (state) {
case SPACE: //如果当前状态(上一个)是空格
if (a[i] == word[0]) {
state = WORD; //变成单词第一个字母状态
} else if (a[i] == ' ') {
state = SPACE;
} else {
state = LETTER; //剩下的肯定是其他字母状态了
}
break;
case LETTER: //是其他字母状态
if (a[i] == ' ') { //空格状态
state = SPACE;
}
break;
default: //是要查找的单词状态
if (state < len) { //还不是最后一个字母
if (a[i] == ' ') {
state = SPACE;
} else if (a[i] == word[state]) {
state++; //变成下一个字母状态
} else {
state = LETTER; //其他状态
}
} else if (state == len) { //是最后一个字母
if (a[i] == ' ') { //如果下一个空格,找到了!
state = SPACE; //状态不要忘记改变
if (ans2 == -1) { //第一次找到,记录下来位置
ans2 = i - len; //因为i是单词的的尾,所以要减长度
}
ans++; //个数加一
} else {
state = LETTER; //可惜,最后跟着其他字母,不是单词
}
}
//break;
}
}
if (state == len) {
ans++;
if (ans2 == -1) {
ans2 = i - len;
}
}
if (ans2 == -1) {
cout<<-1;
} else {
cout<<ans<<" "<<ans2;
}
}