ACM题集:https://blog.csdn.net/weixin_39778570/article/details/83187443
P1219 八皇后
题目:https://www.luogu.org/problemnew/show/P1219
题意:N皇后问题求解个数,部分输出
解法:回溯搜索每一行放置在哪一列就行
#include<bits/stdc++.h>
#define ll long long
#define fo(i,j,n) for(register int i=j; i<=n; ++i)
using namespace std;
int n;
int a[20],ans=0;
bool use[20];
bool ok(int row, int col){
fo(i,1,row-1){
if(a[row-i]-col==i || col-a[row-i]==i) return 0;
}
return 1;
}
void PF(){
fo(i,1,n){
printf("%d%c",a[i],i==n?'\n':' ');
}
}
void dfs(int row){
if(row>n){
ans++;
if(ans<=3)PF();
return;
}
fo(i,1,n){
if(!use[i] && ok(row,i)){
a[row]=i;
use[i] = 1;
dfs(row+1);
use[i] = 0;
}
}
}
int main(){
scanf("%d",&n);
dfs(1);
cout<<ans<<endl;
return 0;
}
P1019 单词接龙
题目:https://www.luogu.org/problemnew/show/P1019
题意:给定n个字符串,若两个字符串有重复部分则可以把两个字符串拼起来,所有字符串能拼接出来的最长字符串的长度
解法:
题目说两个拼接之后,另外相邻的两部分不能存在包含关系
就是说如果存在包含关系,就不能标记为使用过,就是at和ation这种,题目没说的很清 楚,就是指两个单词合并并且包含不能标记为使用过
上面那句话其实是提供了一个剪枝的条件,当重复字符串长度达到左字符串或者右字符串长度是不选
(ps:不剪也可以过啦…因为枚举的时候一样枚举选和不选两种情况啦)
这道题可以不使用string拼接
先看一下这组数据
3
actti s1
iox s2
ttioxasssss s3
a
13
s1,s2,s3个字符串和s1,s3字符串拼起来的长度是一样的,都是13
我们可以"敏锐地"发现,当中间字符串s2被右串包含s3的时候(该串不能单独和右串拼 接,iox和ttioxasssss不能拼接)
我们是可以"忽略"中间这个字符串的,因为它对长度并没有贡献
当s1包含s2的情况也是,s2没有贡献
所以我们不用考虑真的把两个字符串拼起来
比如字符串 s1, s2, s3
拼接 s3 的时候
s1和s2能拼接的情况我们只需要考虑
s2 是否能与 s3拼接
s1 是否能与 s3拼接这两种情况
具体做法我们在每次dfs的时候,每次让新加入的串作为"原串"去比较,每次只需要递归长度就行了
#include<bits/stdc++.h>
#define ll long long
#define fo(i,j,n) for(register int i=j; i<=n; ++i)
using namespace std;
string str[25];
int n,max_len;
int vis[25];
int check(string s1, string s2){
int len = min(s1.length(), s2.length());
int k = s1.length();
fo(i,1,len){
// 从小到大枚举长度i
bool f = 1;
for(int j=0; j<i; j++){
// 检查长度为i是否能匹配成功
if(s1[k-i+j] != s2[j]) f=0; // 出现不同
}
if(f)return i; // 贪心选择最小重叠
}
return 0;
}
void dfs(string now, int len){
max_len = max(max_len, len);
fo(i,1,n){
if(vis[i]==2)continue;
int k = check(now,str[i]);
if(k==len||k==str[i].length())continue; // 包含关系,可以剪枝,删了这一行也不会超时
if(k>0){
// 如果有重叠的话,可以选也可以不选
vis[i]++;
dfs(str[i], len+str[i].length()-k);
vis[i]--;
}
}
}
int main(){
cin>>n;
fo(i,1,n)cin>>str[i];
char c;
cin>>c;
fo(i,1,n){
if(str[i][0]==c){
vis[i]++;
dfs(str[i],str[i].length());
vis[i]--;
}
}
cout<<max_len<<endl<<endl;
return 0;
}
P1101 单词方阵
题目:https://www.luogu.org/problemnew/show/P1101
题意:给一n×n的字母方阵,内可能蕴含多个“yizhong”单词。单词在方阵中是沿着同一方向连续摆放的。摆放可沿着 8 个方向的任一方向,同一单词摆放时不再改变方向,单词与单词之间可以交叉,因此有可能共用字母。输出时,将不是单词的字母用*代替,以突出显示单词。
解法:搜索方阵中