zoukankan      html  css  js  c++  java
  • 单词接龙

    单词接龙

    https://www.luogu.com.cn/problem/P1019

    前言:

    DFS【普及/提高-】的一道好题,当年NOIp2000提高组第三题

    吐槽一下,这道题,解题关键根本就不是DFS哇,重难点完全就是预处理好吧!?

    题目简述:

    给定n个单词,和一个开头字母st,每个单词可以使用两次

    要求找到以st开头的单词接上能与之相接的单词的最长长度

    规则:两个单词之间有重叠部分才能够相接,但是如果两个单词之间是包含关系则两个单词不能相接


    解题思路:

    (1)输入完毕后,对于每两个单词之间,预处理出它们的重叠部分(注意:两个单词互换位置后的重叠部分与互换之前是不一样的)

    (2)接下来,让我们来研究一下这个预处理(大家可以用草稿本模拟一下):

    ①我们用lap[i][j]来表示单词i和单词j之间的重叠长度(注意顺序)

    ②我们用overlap函数来处理两个单词之间的重叠部分

    ③在overlap函数中,用lenx和leny分别存储单词x和单词y的长度,然后双重循环处理

    ④第一层循环i从lenx~1到0(即倒序搜寻单词x),当word[x][i]等于单词y的第一个字母时,进入第二层循环

    ⑤设置k=i,第二层循环j从0~leny(正序遍历单词y),当word[x][k]==word[y][j]时,k++;否则跳出第二层循环

    ⑥每一次跳出第二层循环后,判断k是否等于lenx,如果是就直接返回k-i(lenx-i);不相等就继续循环

    ⑦如果第一层循环完之后,k都始终不等于lenx,则说明两个单词没有重叠部分,返回0

    (3)烧脑的预处理结束后,就简单了,直接循环单词列表,如果当前单词的首字母等于开头字母st,就进入DFS找出以当前单词能连成的最大长度sum,每找完一次(用pd来标记)就用ans选出最大值,最后输出ans即可

    (4)DFS部分和模板差不多,只是需要注意判断一下当前单词是否已经用过两次,是的话就直接不考虑这个单词(用一个ti数组来存储次数即可);而且要注意回溯完整:sum、ti都需要回溯


    代码Code:

    希望预处理部分大家能明白原理qwq,现在给出完整代码

    #include <bits/stdc++.h>
    using namespace std;
    int n,h,sum,ans,lap[10001][10001],ti[10001];
    char st;
    string word[10001];
    
    inline int overlap(int x,int y) { //预处理算出每两个字符串的重叠部分 
    	int lenx=word[x].length(),leny=word[y].length();
    	for(register int i=lenx-1;i>=0;i--) {
    		if(word[x][i]==word[y][0]) {
    			int k=i;
    			for(register int j=0;j<leny;j++) {
    				if(word[x][k]==word[y][j]) k++;
    				else break;
    			}
    			if(k==lenx) return k-i;
    		}
    	} 
    	return 0;
    } 
    
    inline void dfs(int now) {
    	bool pd=false;
    	for(register int i=1;i<=n;i++) {
    		if(lap[now][i]==0) continue;
    		if(ti[i]>=2) continue;
    		if(lap[now][i]==word[now].length()||lap[now][i]==word[i].length()) continue;
    		sum=sum+word[i].length()-lap[now][i];
    		ti[i]++;
    		pd=true;
    		dfs(i);
    		ti[i]--;
    		sum=sum-word[i].length()+lap[now][i];
    	}
    	if(pd==false) {
    		ans=max(ans,sum);
    	}
    	return ;
    }
    
    int main () {
    	scanf("%d",&n);
    	for(register int i=1;i<=n;i++) {
    		cin>>word[i];
    	}
    	cin>>st;
    	for(register int i=1;i<=n;i++) {
    		for(register int j=1;j<=n;j++) {
    			lap[i][j]=overlap(i,j);
    //			cout<<word[i]<<" "<<word[j]<<"="<<lap[i][j]<<endl;
    		}
    	}
    	for(register int i=1;i<=n;i++) {
    		if(word[i][0]==st) {
    			sum=word[i].length();
    			ti[i]++;
    			dfs(i);
    			ti[i]=0;
    		}
    	}
    	printf("%d",ans);
    	return 0;
    }
    

  • 相关阅读:
    HDU 1520 Anniversary party(简单树形DP)
    HDU 4398 Template Library Management(贪心,STL)
    HDU 2829 Lawrence(斜率优化DP)
    HDU 2993 MAX Average Problem(斜率优化DP)
    HDU 3507 Print Article(斜率DP优化)
    转:操作系统各大公司笔试题汇总
    转载 ANSI、Unicode、UTF8相互转化的函数
    2011 各大IT公司笔试面试题目
    Windows Media Format SDK系统概述
    limits.h
  • 原文地址:https://www.cnblogs.com/Eleven-Qian-Shan/p/13098671.html
Copyright © 2011-2022 走看看