日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

洛谷-DFS-1019-单词接龙-个人AC题解和公共AC题解笔记

發(fā)布時間:2023/12/10 编程问答 25 豆豆
生活随笔 收集整理的這篇文章主要介紹了 洛谷-DFS-1019-单词接龙-个人AC题解和公共AC题解笔记 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

學(xué)習(xí)內(nèi)容:

  • 預(yù)處理
  • 萬能頭文件
  • string的使用


    話不多說,直奔主題

本人AC代碼

#include<iostream> #include<cstdio> #include<cstring> using namespace std; #define MAXN 21 #define MAXLENGTH 21 int n; int length,max_length; char words[MAXN][MAXLENGTH]; char current_word[1000]; int book[MAXN]; inline void add(int order,int start)//進(jìn)行單詞連接 {book[order]++;int len=strlen(words[order]);while(start<len){current_word[length]=words[order][start];length++;start++;}current_word[length]='\0'; } inline int match(int order,int start)//檢查是否匹配 {//cout<<"match"<<endl;int t=0;int i;int len;for(i=start;i<length;i++,t++){if(current_word[i]!=words[order][t]){return 0;}}len=length-start;return len; } inline int check(int order,int word_length)//check {int flag=0;int start;for(int i=length-1;i>=length+1-word_length;i--){if(current_word[i]==words[order][0]){start=match(order,i);if(start){add(order,start);flag=1;return flag;}}}return flag; } inline void dfs()//普通的dfs啊 {char word[1000];int len1;strcpy(word,current_word);len1=strlen(current_word);int len;if(length>max_length){max_length=length;}for(int i=0;i<n;i++){if(book[i]==2){continue;}len=strlen(words[i]);if(!check(i,len)){continue;}dfs();book[i]--;strcpy(current_word,word);length=len1;}return; } int main() {char origin_letter;cin>>n;for(int i=0;i<n;i++){cin>>words[i];}cin>>origin_letter;for(int i=0;i<n;i++){if(words[i][0]!=origin_letter){continue;}memset(book,0,sizeof(book));length=0;strcpy(current_word,words[i]);length=strlen(words[i]);book[i]++;if(length>max_length){max_length=length;}dfs();}cout<<max_length;return 0; }

自己的思路:看到題目分類是dfs,自然采取dfs作為核心思路,但是對比公共題解,發(fā)現(xiàn)可以采取更好的辦法,即采取預(yù)處理的方法,預(yù)處理思路如下:

? 1.'龍’的每個部分都是由單詞連接而成,那么其實可以拆分成兩兩單詞連接.
? 2.所以提前判斷兩個單詞之間是否可以進(jìn)行連接,用數(shù)組存下前單詞與后單詞之間的疊數(shù),之后操作就變得簡單.

附上洛谷題解代碼:

#include<cstdio> #include<iostream> #include<string> #include<cmath> using namespace std; int n;//單詞數(shù) string tr[30];//存儲字符串 int yc[30][30];//兩個字母的最小重疊部分 int vis[30];//判斷單詞使用頻率. int mt(int x, int y){//mt函數(shù),返回x單詞后連接一個y單詞的最小重疊部分 bool pp=true; int ky=0;for(int k=tr[x].size()-1;k>=0;k--){//從x單詞尾部向前看看最小重疊部分是從哪里開始的,以為因為是倒著來,所以保證是最小的 for(int kx=k;kx<tr[x].size();kx++){if(tr[x][kx]!=tr[y][ky++]){pp=false;break;}}if(pp==true){//如果說當(dāng)前以k為開頭的前一個單詞后綴 ,是后面單詞的前綴,就馬上返回重疊部分。(tr[x].size()-k是找出來的規(guī)律)return tr[x].size()-k; } ky=0;pp=true;//不行就繼續(xù)}return 0; }//可能這里有點難理解。可以手動模擬一下 char ch;//開頭字母 int ans=-1;//答案 int an=0;//每次搜到的當(dāng)前最長串 void dfs(int p){//p為尾部單詞編號(p的后綴就是“龍”的后綴,因為p已經(jīng)連接到”龍“后面了)bool jx=false; for(int j=1;j<=n;j++){if(vis[j]>=2) continue;//使用了兩次就跳過 if(yc[p][j]==0) continue;//兩單詞之間沒有重合部分就跳過 if(yc[p][j]==tr[p].size() || yc[p][j]==tr[j].size()) continue;//兩者存在包含關(guān)系就跳過 an+=tr[j].size()-yc[p][j];//兩單詞合并再減去最小重合部分 vis[j]++;//使用了一次jx=true;//標(biāo)記一下當(dāng)前已經(jīng)成功匹配到一個可以連接的部分 dfs(j); //接上去an-=tr[j].size()-yc[p][j];//回溯,就要再減回去那一部分長度 vis[j]--;//回溯,使用-- }if(jx==false){//jx==false說明不能再找到任何一個單詞可以相連了 ans=max(ans,an);//更新ans }return; } int main(){scanf("%d",&n);for(int i=1;i<=n;i++)cin>>tr[i];cin>>ch; for(int i=1;i<=n;i++){for(int j=1;j<=n;j++){yc[i][j]=mt(i,j); }}//預(yù)處理yc數(shù)組。yc[i][j]就表示,i單詞后連接一個j單詞的最小重疊部分 //比如 i表示at,j表示att. yc[i][j]就為2 但是yc[j][i]就為0.//預(yù)處理是一個關(guān)鍵for(int i=1;i<=n;i++){//從頭到尾看一下有沒有以指定開頭字母為開頭的單詞 if(tr[i][0]==ch){//如果有,就以當(dāng)前單詞為基準(zhǔn)進(jìn)行搜索。 vis[i]++;//使用過一次 an=tr[i].size();//更新當(dāng)前串長度 dfs(i);//接上vis[i]=0;//消除影響 } } printf("%d",ans);return 0; }

相比起來,自己的代碼采取的是邊選取邊判斷的思路,明顯使代碼變得冗余,所以預(yù)處理這里是一個優(yōu)化的點.

這里有個隱性的問題需要提到,比如單詞A為"abcd",單詞B為"defgh",單詞c為abcdefghijk,如果僅是兩兩單詞之間判斷是否可以連接的話,那么明顯可以采取的方式只有AB,AC,但是如果’龍’是AB,即"abcdefgh",那么這時候C可以連在龍尾,即ABC,而如果二二單詞連接而成的話,BC是不允許的,但是考慮到采取ABC連接和AC連接,最后的效果是一樣的,而且AC連接還可以省出一個B,可能可以為后面的’龍’添加長度,所以AC更加,這在無形中使得二二連接方式直接省略這一步的考慮,因洛谷題解未提出,因防止有人有相同疑問,故在此講解

此外,說一下題解二,先附上代碼

#include<bits/stdc++.h> using namespace std; string str[20]; int use[20], length = 0, n; int canlink(string str1, string str2) {for(int i = 1; i < min(str1.length(), str2.length()); i++) {//重疊長度從1開始,直到最短的字符串長度-1(因為不能包含)int flag = 1;for(int j = 0; j < i; j++)if(str1[str1.length() - i + j] != str2[j]) flag = 0;//逐個檢測是否相等if(flag) return i;//檢測完畢相等則立即return}return 0;//無重疊部分,返回0 } void solve(string strnow, int lengthnow) {length = max(lengthnow, length);//更新最大長度for(int i = 0; i < n; i++) {if(use[i] >= 2) continue;//該字符串使用次數(shù)需要小于2int c = canlink(strnow, str[i]);//獲取重疊長度if(c > 0) {//有重疊部分就開始dfsuse[i]++;solve(str[i], lengthnow + str[i].length() - c);use[i]--;}} } main() {cin >> n;for(int i = 0; i <= n; i++) use[i] = 0, cin >> str[i];//str[n]為開始字符 solve(' '+str[n], 1);//有必要解釋一下開始階段。為了指定第一個字符,而且因為canlink需要重疊部分小于最短長度-1,所以要從前面添加一個無意義充長度的‘ ’。這樣就強制了canlink函數(shù)比較最后一位。cout << length ; }

對于題解二,第一眼看到就很驚艷,自己代碼長的一批,對題解中答主注釋的追求簡潔的態(tài)度很是認(rèn)同,同時此題采用的也是預(yù)處理的操作,然后就是學(xué)到的幾點:

  • 萬能頭文件:bits/stdc++.h
  • string數(shù)據(jù)類型的一些使用
    • 方法:length()
    • 和其他語言類似的’+'來連接string

在這里提一嘴,倒數(shù)第三行中的’ ‘就像答主說的因為canlink函數(shù)中的重疊長度為最小長度減一,所以這里得放一個’ ‘來占長度,但是我覺得這個操作mmm,跟題解評論一樣,顯得可讀性太差,不如加一個判斷來得到’龍頭’,個人意見,不喜勿噴

后面題解思路接近,END.

?
?

總結(jié)

以上是生活随笔為你收集整理的洛谷-DFS-1019-单词接龙-个人AC题解和公共AC题解笔记的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。