自動狀態機
圖靈機大概就是一個“自動機”,就是說代碼分好幾種狀態,每種狀態做不同的事。
舉個簡單的例子吧
輸入一個字符串,輸入的只有兩種字符,一種是字母,一種是空格。現在求一共有幾個單詞。注意,有可能有多個空格連在一起,開頭和結尾都有可能有空格。
那么這是一道簡單的有窮自動機,運行時分兩種情況:
①是空格
②是字母
(其實當前狀態就是上一個字符的狀態
那么在遍歷數組的時候拿一個變量記錄下來當前是什么狀態,可以用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;
}
}