P1706
啊先来夸一夸next_permutation
#include <iostream>
#include <algorithm>
using namespace std;
int main() {
int a[10];
int n;
cin >> n;
for(int i = 1; i<= n; i++) {
a[i] = i;
}
do {
for(int i = 1; i <= n; i++) {
cout << " " <<a[i];
}
cout << endl;
}while(next_permutation(a + 1, a + n + 1));
return 0;
}
然后就用递归来做吧,就是在里面放一个for循环,然后每一次要标注,要还回去,记录的东西是搜索的数量,为了打印还要保存在数组里面,用的也是搜索的数量来标志数组
#include<bits/stdc++.h>
using namespace std;
int n,pd[100],used[100];//pd是判断是否用过这个数
void print()//输出函数
{
int i;
for(i=1;i<=n;i++)
printf("%5d",used[i]);//保留五位常宽
cout<<endl;
}
void dfs(int k)//深搜函数,当前是第k格
{
int i;
if(k==n) //填满了的时候
{
print();//输出当前解
return;
}
for(i=1;i<=n;i++)//1-n循环填数
{
if(!pd[i])//如果当前数没有用过
{
pd[i]=1;//标记一下
used[k+1]=i;//把这个数填入数组
dfs(k+1);//填下一个
pd[i]=0;//回溯
}
}
}
int main()
{
cin>>n;
dfs(0);//注意,这里是从第0格开始的!
return 0;
}
P1219
哟西,八皇后问题
主要是如何标记不能再放的点,左边倾斜的对角线是它的横纵坐标和是相同的,向右边倾泄的是相减相同,用这个特点可以确定每一行不能放的列数,然后就用递归,放在哪些可以放的,dfs的参数还是递归了几次,每一次是循环每一列,满足三个条件,然后注意为了不越界,所以右斜就全部+n
每个不同的x对应不同的i,但是是有关系的
#include<iostream>
using namespace std;
int n,cnt;
bool lie[20];//列
bool u[20];//左上到右下
bool v[40];//右上到左下
int a[20];
void pr()
{
if(cnt<=3)
{
for(int i=1;i<=n;i++)
{
cout<<a[i]<<" ";
}
cout<<endl;
}
}
void dst(int x)
{
if(x>n)
{
cnt++;
pr();
return;
}
for(int i=1;i<=n;i++)
{
if(!lie[i]&&!u[x-i+n]&&!v[x+i])
{
lie[i]=1;
u[x-i+n]=1;
v[x+i]=1;
a[x]=i;
dst(x+1);
lie[i]=0;
u[x-i+n]=0;
v[x+i]=0;
}
}
}
int main()
{
cin>>n;
dst(1);
cout<<cnt;
}
P1605
这个就是很没有意思的广搜啦
看一下模板,循环多少种走法,然后得出出来可能的下一步,判断可以不可以走(越界||数据不对||不可以||走过来||,然后打上标记,继续深搜它,最后搜到结果就++
#include<iostream>
using namespace std;
int xx[]={-1,0,1,0};
int yy[]={0,1,0,-1};
bool mp[100][100]={0};
bool qia[100][100]={0};
int c,k,za,qix,qiy,zhx,zhy,a,cnt=0,b,dx,dy,x,y;
void dfs(int x,int y)
{
if(x==zhx&&y==zhy)
{
cnt++;
return;
}
for(int i=0;i<4;i++)
{
int dx=x+xx[i];
int dy=y+yy[i];
if(!mp[dx][dy]&&dx<=c&&dx>=1&&dy<=k&&dy>=1&&!qia[dx][dy])
{
mp[dx][dy]=1;
dfs(dx,dy);
mp[dx][dy]=0;
}
}
}
int main()
{
cin>>c>>k>>za;
cin>>qix>>qiy>>zhx>>zhy;
for(int i=1;i<=za;i++)
{
cin>>a>>b;
qia[a][b]=1;
}
mp[qix][qiy]=1;
dfs(qix,qiy);
cout<<cnt;
}
P1101
这其实就是八个方向,连续的,先找到头,然后八个方向连续的都要满足,所以需要两重循环,一重确定方向,一重高歌猛进
#include<iostream>
using namespace std;
int m;
int p=1,flag;
char a[1100][1100];
int xx[]={-1,-1,-1,0,0,1,1,1};
int yy[]={-1,0,1,1,-1,1,0,-1};
int vis[1100][1100]={0};
string yz="yizhong";
void dfs(int x,int y)
{
for(int i=0;i<8;i++)
{ int flag=1;
for(int j=0;j<7;j++)
{
int dx=x+xx[i]*j;
int dy=y+yy[i]*j;
if(yz[j]!=a[dx][dy]||!(dx>=1&&dx<=m&&dy>=1&&dy<=m))
{flag=0;
break;
}
}
if(flag)
{
for(int j=0;j<7;j++)
{
int dx=x+xx[i]*j;
int dy=y+yy[i]*j;
vis[dx][dy]=1;
}
}
}
}
int main()
{
cin>>m;
for(int i=1;i<=m;i++)
{
for(int j=1;j<=m;j++)
{
cin>>a[i][j];
}
}
for(int i=1;i<=m;i++)
{
for(int j=1;j<=m;j++)
{
if(a[i][j]=='y')
dfs(i,j);
}
}
for(int i=1;i<=m;i++)
{
for(int j=1;j<=m;j++)
{
if(!vis[i][j])
cout<<"*";
else
cout<<a[i][j];
}
cout<<endl;
}
return 0;
}
P1019
你需要他更加的长,所以是从最后一个来对照,然后向前走,每一个只能出现两遍
首先遍历所有的,找合适的头,找到深搜,记得还原
深搜内部要记录最长的答案
然后开始循环,记录两者的长度,while循环
然后用一个神奇的s.substr(la-p)==a[i].substr(0,p)
形式 : s.substr(pos, len)
返回值: string,包含s中从pos开始的len个字符的拷贝(pos的默认值是0,len的默认值是s.size() - pos,即不加参数会默认拷贝整个s)
下一步深搜的长度是l+lb-p,两个人合起来减去重复的
#include<iostream>
#include<string.h>
#include<algorithm>
using namespace std;
int vis[22];
int ans,m,p;
string a[100];
char c;
void dst(string s,int l)
{
ans=max(ans,l);
for(int i=1;i<=m;i++)
{
int p=1;
int la=s.length();
int lb=a[i].length();
while(p<min(la,lb))
{
if(s.substr(la-p)==a[i].substr(0,p)&&vis[i]<2 )
{
vis[i]++;
dst(a[i],lb+l-p);
vis[i]--;
break;
}
p++;
}
}
}
int main()
{
cin>>m;
for(int i=1;i<=m;i++)
{
cin>>a[i];
}
cin>>c;
for(int i=1;i<=m;i++)
{
if(a[i][0]==c)
{
vis[i]++;
dst(a[i],a[i].length());
vis[i]--;
}
}
cout<<ans;
}
听刘露阳的话,好好学基础
#include<cstdio>
#include<iostream>
#include<string>
using namespace std;
struct word{
string line;
int left=2;
}w[25];
int n,maxA;
inline int find(int last,int next)
{
int lenl=w[last].line.length(),lenn=w[next].line.length();
for(int i=lenl-1;i>=1;--i)
{
if(w[last].line[i]==w[next].line[0])
{
int k=i,j=0,cl=0;
while(j<lenn && k<lenl)
{
if(w[last].line[k]==w[next].line[j])++cl;
else return 0;
++k;++j;
}
if(k==lenl && j<lenn)return cl;
else return 0;
}
}
return 0;
}
inline void dfs(int now,int length)
{
bool flag=false;//所谓的标志变量
for(int i=1;i<=n;i++)
{
if(!w[i].left)continue;//一个单词只能用两次;
else
{
int x=find(now,i);
if(x)
{
flag=true;//搜到变成真
--w[i].left;
length+=(w[i].line.length()-x);
dfs(i,length);
++w[i].left;
length-=(w[i].line.length()-x);
//这边不仅编号要回溯,长度也要回溯(卡了我很久)
//至于为什么,就是因为dfs结束,返回到了这里,那么dfs这一趟完了,这个长度和次数还要用到下一次搜索当中去。
}
else flag=false;//标志变量为假就是搜完了,没有可连接单词;
}
}
if(!flag) maxA=max(maxA,length);
}
int main()
{
scanf("%d",&n);
//for(int i=1;i<=n;i++)w[i].left=2;
for(int i=1;i<=n;i++)cin>>w[i].line;
char p=getchar();cin>>p;
//输入完成;
for(int i=1;i<=n;i++)
{
if(w[i].line[0]==p)
{
--w[i].left;
dfs(i,w[i].line.length());
++w[i].left;
//这边也要回溯,同上。
}
}
printf("%d",maxA);//最后输出最大值;
return 0;
}
P1162
比和空间:绝对不是循环www,可以在外面套一层0,然后就把他围起来了,然后把这些0都标志上,那么没标志的0,就是要变成2的了
使用广搜,上下左右
#include<iostream>
#include<queue>
using namespace std;
queue <int> x;
queue <int> y;
int xx[]={1,0,-1,0};
int yy[]={0,-1,0,1};
int vis[31][31]={0};
int a[31][31];
int m,dx,dy;
int main()
{
cin>>m;
for(int i=1;i<=m;i++)
{
for(int j=1;j<=m;j++)
{
cin>>a[i][j];
}
}
x.push(0);
y.push(0);
a[0][0]=0;
while(!x.empty() )
{
for(int i=0;i<4;i++)
{
dx=x.front() +xx[i];
dy=y.front() +yy[i];
if(dx>=0&&dx<=m+1&&dy>=0&&dy<=m+1&&a[dx][dy]==a[x.front() ][y.front() ]&&!vis[dx][dy])
{
x.push(dx);
y.push(dy);
vis[dx][dy]=1;
}
}
x.pop() ;
y.pop() ;
}
for(int i=1;i<=m;i++)
{
for(int j=1;j<=m;j++)
{
if(a[i][j]==0&&vis[i][j]==0)
{
a[i][j]=2;
}
cout<<a[i][j]<<" ";
}
cout<<endl;
}
}
P1443
走到棋盘上任意一点,进行广搜
#include<iostream>
#include<queue>
#include<cstring>
using namespace std;
int xx[]={-2,-2,-1,-1,1,1,2,2};
int yy[]={1,-1,2,-2,2,-2,1,-1};
struct Node
{
int x;
int y;
int t;
};
queue <Node> Q;
int n,m,qi,zh,dx,dy;
int vis[401][401];
int main()
{
cin>>n>>m;
cin>>qi>>zh;
Q.push((Node){qi,zh,0});
memset(vis,-1,sizeof(vis));
vis[qi][zh]=0;
while(!Q.empty() )
{
for(int i=0;i<=7;i++)
{
int dx=xx[i]+Q.front().x;
int dy=yy[i]+Q.front().y;
if(dx>=1&&dx<=n&&dy>=1&&dy<=m&&vis[dx][dy]==-1)
{
vis[dx][dy]=Q.front().t+1;
Q.push((Node){dx,dy,Q.front().t+1});
}
}
Q.pop();
}
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
printf("%-5d ",vis[i][j]) ;
}
cout<<endl;
}
return 0;
}
P1141
询问可以到那个格子,那么意味着这一片地方都是一个值,然后是否访问可以直接计成colour,来区分不同的colour走的cnt,cnt++一定要放在最后,以出队的个数为准,然后把coulour放到ans里面,cnt就是它的值,coulour,就是visit[x][y]
#include<iostream>
#include<queue>
using namespace std;
int xx[]={1,0,-1,0};
int yy[]={0,1,0,-1};
int vis[1001][1001]={0},colour=0,dx,dy,m,cnt,n;
int ans[1000];
int mp[1001][1001]={0};
void bst(int i,int j)
{
queue<int>x;
queue<int>y;
x.push(i);
y.push(j);
vis[i ][j ]=colour;
while(!x.empty())
{
for(int i=0;i<=3;i++)
{
dx=x.front() +xx[i];
dy=y.front() +yy[i];
if(dx>=1&&dx<=m&&dy>=1&&dy<=m&&!vis[dx][dy]&&mp[dx][dy]!=mp[x.front()][y.front()])
{
vis[dx][dy]=colour;
x.push(dx);
y.push(dy);
}
}
x.pop() ;
y.pop() ;
cnt++;///cnt的位置
}
}
int main()
{
char c;
cin>>m>>n;
for(int i=1;i<=m;i++)
{
for(int j=1;j<=m;j++)
{
cin>>c;
if(c=='1')
mp[i][j]=1;
if(c=='0')
mp[i][j]=0;
}
}
for(int i=1;i<=m;i++)
{
for(int j=1;j<=m;j++)
if(!vis[i][j])
{
++colour;
bst(i,j);
ans[colour]=cnt;
cnt=0;
}
}
for(int i=1;i<=n;i++)
{
int hx,hy;
cin>>hx>>hy;
cout<<ans[vis[hx][hy]]<<endl;
}
}
P1604
来看看进制转化的实质,应该是不需要十进制作为中间商了
前面就都当做正常的高精度计算(毕竟你需要把ABCD转化)
然后直到相加得到c,c得到之后要进位,进位的时候整除和取余要用到c
#include<iostream>
#include<algorithm>
#include<cstring>
#include<math.h>
using namespace std;
string s1,s2;
int a[100089],b[100089],la,lb,lc,c[100032];
int main()
{
int n;
cin>>n;
cin>>s1>>s2;
la=s1.length() ;
lb=s2.length() ;
for(int i=0;i<la;i++)
{
if(s1[i]<='9')
{
a[la-i]=s1[i]-'0';
}
else
{
a[la-i]=s1[i]-'A'+10;
}
}
for(int i=0;i<lb;i++)
{
if(s2[i]<='9')
{
b[lb-i]=s2[i]-'0';
}
else
{
b[lb-i]=s2[i]-'A'+10;
}
}
lc=max(la,lb)+1;
for(int i=1;i<=lc;i++)
{
c[i]+=a[i]+b[i];
c[i+1]+=c[i]/n;
c[i]%=n;
}
while(c[lc]==0&&lc>1)
lc--;
for(int i=lc;i>=1;i--)
{
if(c[i]>=10)
cout<<char(c[i]-10+'A');
else
cout<<c[i];
}
}