关于洛古p1019单次接龙的一点看法

/*
注:原题解转载的其他人的,只是加了一些个人想法 
1.lin为存单词的数组,t为输入单词的个数,vis数组存的是使用的次数,、
len数组表示没一个单词的长度 。
2.此题目的状态是单词的位置和长度(i,length)
*/ 

#include<iostream>  
#include<cstring>  
#include<cmath>  
using namespace std;  
struct node{  
    char lin[1000];  
}s[20];  // 结构体 s 用于储存单词 
/*
此步解决了保存单词的问题,使可以一个一个字母的保存,
反思也可以在输入一些单词,按单词长度从大到小输出 
*/  
int t,ans;  
int vis[20];  //标记数组,每一次搜索初始化为 0,单词使用一次加一,超过二就不能继续使用 ,即小于等于2.  
int len[20];  //单词长度数组,表示每一个单词的长度   
/*
found函数
stp选择的上一个单词下标,i为后一个,例子在后面
首先 进行for循环,循环的意义也就是从之前的单词最后一个开始和
后面的单词从前向后比较。
所以总结一下循环的意义
1.在dp中确定长度l和范围
2.在字符串搜索中是两个单词比较,可参照kmp算法。

 如果(if)在for循环中的q与后面单词的第一个字母相等,那就好办了,直接往后搜索。
  做判断用的。
  然后定义一个相同位数,后面dfs说过。从q开始向前一个单词最后一个字母前进,
  后面的单词从第一个字母向后面前进,一一比较。
  比较不过的内层for循环就break。注意!一定要比到上一个字符的最后一个字符答案才有效
   因为要从 最后一个字母接嘛。然后返回x。 
*/

int found(int stp,int i){ //stp代表上一个已经选择的单词下标 i表示当前的单词下标   
    int q,w,j;  
    for(q=len[stp]-1;q>=1;q--){   //为使长度最长,从上一个单词的末尾开始搜索   
        if(s[stp].lin[q]==s[i].lin[0]){  //第一个字符匹配后继续看后面还有多少位   
            int x=0;         //相同位数   
            for(w=q,j=0;w<len[stp]&&j<len[i];w++,j++){  
                if(s[stp].lin[w]==s[i].lin[j])x++;  
                else break;  
            }  
            if(w==len[stp])return x;//注意!一定要比到上一个字符的最后一个字符答案才有效   
        }  
    }  
    return 0;  
}  
/*
dfs函数
dfs函数的状态就是(i,length),也就是已知量,目的是求输出
以此字母开头的最长的“龙”的长度。
 stp指的是上一个已经选择的单词,也就是“i” 
*/

void dfs(int stp,int length){ //上一个已经选择的单词  当前的最长单词长度   
    int i;  
    bool mark=false;//以旗子来判断,是否找到  
    for(i=0;i<t;i++){  
        if(vis[i]>2)continue;//单词已经被找过两次以上,跳过   
        int x=found(stp,i);  //x代表上一个单词与当前单词的匹配位数   
        if(x!=0){   //匹配位数不为0就继续进行下一次的单词搜索   
            mark=true;  
            length+=(len[i]-x);  //当前长度增加
			//举个例子,比如length和theacter,这两个单词有th这两个字母
			//重合的,所以结合就是lengtheacter,所以length+=(len[i]-x);   
            vis[i]+=1;    //当前单词用过一个加一   
            dfs(i,length);//然后i就变成了“上一个”继续去找了。  
            //上一步递归不符合题意返回至此,长度减去不符合题意的单词,单词的使用次数减一,继续选择单词   
            length-=(len[i]-x);  //回溯法原理。 
            vis[i]-=1;  
        }  
    }  
    if(mark==false){     //如果已经找不到单词,比较之前已经得到过的答案选择最长的单词数   
        ans=max(ans,length);  
    }  
}  
int main(){  
    int i;  
    char l1;  
    cin>>t;  
    for(i=0;i<t;i++){  
        cin>>s[i].lin;  
        len[i]=strlen(s[i].lin);  
    }  
    cin>>l1;  
    ans=0;  
    memset(vis,0,sizeof(vis));  //初始化单词标记数组  
    for(i=0;i<t;i++)if(s[i].lin[0]==l1){  
        vis[i]++; //每个单词使用一次,一个一个来。   
        dfs(i,len[i]);//当前使用的单词下标与长度   
    }  
    cout<<ans;//输出结果   
    return 0;  
}

看法都在注释里面
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值