201803-4 棋局評估
這道題當初卡了我不知道多少遍,每次動手想做一下CSP認證的第三道題,都從這道題開始,但每次都被卡住。直接是連題意都有點讀不懂,但是讀懂了之後就會發現,這道題除了特別繁瑣之外,好像也沒用到什麽很難的算法。
借鑒了這位大佬的思路:https://blog.csdn.net/xbb224007/article/details/79962425?utm_source=blogxgwz0
我沒發現比這個還簡潔的代碼,所以就學了一下這個思路,比較容易理解。
對這道題,我其實是無從下手的。究其原因,在於:1.字符串匹配的題目做的太少了,沒做幾道。2.不太會stringstream流操作,所以對復雜的字符串操作不夠靈活。3.數據結構沒想出來,不知道用什麽來存這麽多的字符串。
題目大意是這樣的,給出一連串匹配規則,以及一連串待匹配字符串。對每個待匹配字符串,要拿每一個規則匹配它,如果匹配成功,就輸出這個規則名稱,以及成功匹配的參數部分(即用題中的str、int、path成功匹配的部分,其他的成功匹配不輸出);如果對所有規則都不匹配,就輸出404。
先開一個一維字符串數組,存放所有原始規則,再開一個二維字符數組,存放每一個原始規則被‘/‘拆分後的部分。再開一個一維整型數組,存放每一條原始規則拆分後的部分數,再開一個記號數組,標記每一條原始數組是否為‘/‘結尾。
之後開一個二重循環,對每一條待匹配語句都對每一條規則進行比較,如果有一個成立就跳出。匹配函數是一個模塊。對每一個語句的匹配,都要拆分開來,一部分一部分匹配,這需要一個拆分函數;對
下面是代碼,部分關鍵地方有註釋。其實很顯然,難就難在對字符串的拆分和匹配上了,數據結構想不出來,拆分不會,這題就是0分了。
程序中有很多小細節,個中巧妙之處,需要細細體會。
#include <bits/stdc++.h> #define N 105 using namespace std; string lim[N],lims[N][N],limname[N]; //lim是第i個規則字符串,lims是第i個規則字符串的拆分,limname是對應字符串的名字 string now,nows[N]; //nows是當前被檢索字符串的拆分 bool isop[N],iso; //isop判斷規則末尾有無斜杠,iso判斷地址末尾有無斜杠 int limcnt[N],nowcnt; //limcnt計數規則的拆分後項數,nowcnt計數當前被檢索字符串的拆分後項數 void stcut(string ori,string cut[],bool& is,int&num); bool match(int j,int nc,string& a); string isnum(string s); int main() { int n,m; cin>>n>>m; for (int i=0;i<n;i++) { cin>>lim[i]>>limname[i]; stcut(lim[i],lims[i],isop[i],limcnt[i]); } for (int i=0;i<m;i++) { cin>>now;iso=0; //註意此處將iso置0 stcut(now,nows,iso,nowcnt); string ans; int f=0; for (int j=0;j<n;j++) { if (match(j,nowcnt,ans)) { string ss=limname[j]+ans; cout<<ss<<endl; f=1;break; } } if (f==0) cout<<404<<endl; } return 0; } //nows是當前字符串,j是當前的判定模塊序號,nc是當前字符串切分後的項數,a是可能的跟在標簽後面的答案字符串 bool match(int j,int nc,string& a) { a=""; int p1=0,p2=0; while (p1<nc&&p2<limcnt[j]) { if (nows[p1]==lims[j][p2]) ; else if (lims[j][p2]=="<int>") { string st=isnum(nows[p1]); if (st=="") return 0; else a+=‘ ‘+st; } else if (lims[j][p2]=="<path>") { a+=‘ ‘+nows[p1++]; while (p1<nc) a+=‘/‘+nows[p1++]; if (iso) a+=‘/‘; return 1; } else if (lims[j][p2]=="<str>") a+=‘ ‘+nows[p1]; else return 0; p1++,p2++; } if (p1<nc||p2<limcnt[j]) return 0; if (isop[j]^iso) return 0; return 1; } //ori是原始字符串,cut是切割後的分塊,is是判斷最後有無‘/‘,num是切分後的項數 void stcut(string ori,string cut[],bool& is,int& num){ int len=ori.size(); string ss; num=0; if (ori[len-1]==‘/‘) is=1; for (int i=0;i<(int)ori.size();i++) if (ori[i]==‘/‘) ori[i]=‘ ‘; stringstream in(ori); while (in>>ss) cut[num++]=ss;; } string isnum(string s) { string ans=""; int ok=0; for (int i=0;i<(int)s.size();i++) { if (s[i]<‘0‘||s[i]>‘9‘) return ""; else if (ok||(s[i]>‘0‘&&s[i]<=‘9‘)) ans+=s[i],ok=1; } return ans; }
201803-4 棋局評估