搜索:
bfs:
int dir[4][2]={{-1,0},{1,0},{0,1},{0,-1}};
struct node
{
int x,y;
}
void bfs()
{
queue<node>q;//定义一个队列。
node start,next;
start.x=dx;
start.y=dy;//坐标代表起始位置。
q.push(start);
while(!q.empty())
{
start.x=q.front();//将队列第一个进行处理。
q.pop();//删除第一个。
for(int i=0;i<4;i++)//这里是向四个方向进行搜索。
{
next.x=start.x+dir[i][0];
next.y=start.y+dir[i][1];
if(next.x>=0&&next.x<tt&&next.y>=0&&next.y<tt&&vis[next.x][next.y]==0)
//这个只是一个判定的条件,要根据题意自己去填写,有点题也用不到标记数组。
{
vis[next.x][next.y]=1;//标记已经走过。
q.push(next);//将新的结构体加入队列。
}
}
}
}
dfs:
void dfs(int x,int y)
{
for(int i=0;i++;i++)
{
int dx=x+dir[i][0];
int dy=y+dir[i][1];
//if(里面也是对新的dx,dy进行判断)
//如果上边使用了标记数组,那么下面要进行解放。如vis[dx][dy]=1;
dfs(dx,dy);
//那么递归结束后要进行解放,vis[dx][dy]=0;
}
}
相比较而言,dfs的代码比较简洁,但是bfs也有他自己的好处,比如求最小的步数到终点等等。
两种搜索各有好处,做题时自己进行选择吧。
并查集
//未优化。
void init_set()//初始化
{
for(int i=1;i<=n;i++){
s[i]=i;
}
}
int find_set(int k)//查找
{
return k==s[k]?k:find_set(s[k]);
}
void union_set(int x,int y)//讲两个有关系的进行关联,将两个集合合成为一个集合。
{
x=find_set(x);
y=find_set(y);
if(x!=y)
s[x]=s[y];
}
{
优化后:
void init_set()//初始化
{
for(int i=1;i<=n;i++){
s[i]=i;
hight[i]=0;//合并节点。将短的树合并到长的数上。
}
}
int find_set(int k)//查找优化,路径压缩
{
if(k!=s[k])
s[k]=find_set(s[k]);//将每个枝都合并到最后的根节点上,方便后遍的查找
return s[k];
}
void union_set(int x,int y)//讲两个有关系的进行关联
{
x=find_set(x);
y=find_set(y);
if(hight[x]==hight[y]){
hight[x]+=1;
s[y]=x;//将y整棵树合并到x这棵数(集合)上
}else
{
if(hight[x]<hight[y]){
s[x]=y;
}
else
s[y]=x;
}
}
路径压缩数据较大担心爆栈,可以用非递归。
int find_set(int k)
{
int t=k;
while(s[t]!=t)//找根。
t=s[t];
int i=k,j;
while(i!=t)
{
j=s[i];
s[i]=t;
i=j;
}
return t;
}
并查集我现在只是学了一个皮毛,之后会继续学,加强对其的理解与熟悉。
基础dp:
01背包:
//二维数组:
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
if(w[i]>j)
dp[i][j]=dp[i-1][j];
else
max(dp[i][j]=dp[i-1][j],dp[i-1][j-w[i]]+v[i]);
}
}
//一维数组
for(int i=1;i<=n;i++){
for(int j=m;j>=w[i];j--){//可以思考一下为什么要到这循环。
dp[j]=max(dp[j],dp[j-w[i]]+v[i]);
}
}
完全背包:
//二维数组
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
dp[i][j]=max(dp[i][j-w[i]]+v[i],dp[i-1][j]);
}
}
//一维数组:
for(int i=1;i<=n;i++){
for(int j=w[i];j<=m;j++){//正序循环
dp[j]=max(dp[j],dp[j-w[i]]+v[i]);
}
}
dp对我现在来说还是太难了,只能写一些比较基础的模板题,所以只写了最简单的背包问题(还不全面)。随着之后的学习会在写。
dp最重要的就是写状态方程。。。。还是要多练习多思考
字符串:
字典树:
int tire[200][26],cnt[200],idx=1;//二维数组存储字符串,cnt数组为一个标记数组
// idx从1开始,根不做处理。
char s[200];
void add(char str[])//添加单词
{
int j=0;
for(int i=0;i<strlen(str);i++){
int x=str[i]-'a';
if(tire[j][z]==0)tire[j][z]=idx++;
j=tire[j][z];
}
cnt[j]++;//字符串结束标记一下
}
int Find(char str[])
{
int j=0;
for(int i=0;i<strlen(str);i++){
int z=str[i]-'a';
if(tire[j][z]==0) return 0;
j=tire[j][z];
}
return cnt[j];
}
kmp:
kmp算法的核心就是求next[]数组。
int Next[1005];//不要定义成next[],在hdu上会出现编译错误。
void get_next(char str[])//得到next数组
{
int len=strlen(str);
int i=0,j=-1;
Next[0]=-1;
while(i<len){
if(j==-1||str[i]==str[j]){
i++;
j++;
Next[i]=j;
}
else
j=Next[j];
}
}
int Find(char str1[],char str2[])//进行查找。
{
int len1=strlen(str1);
int len2=strlen(str2);
int i=0,j=0,ans=0;
while(i<len1)
{
if(j==-1||str1[i]==str2[j])
{
i++;
j++;
}
else
j=Next[j];
if(j==len2)
{
ans++;
j=0;//根据题目要求来写回溯到的位置,j=next[j];
}
}
return ans;
}
循环的节数=字符串长度–此时next[]数组的数值。
即:len1=len-Next[ len ];
如 abbhkkdabb 循环长度为 7;
最短路:
Floyd:
for(int k=1;k<=n;k++){
for(int i=1;i<=n;i++){
if(mp[i][k]!=INF)//小优化
for(int j=1;j<=n;j++){
if(mp[i][j]>mp[i][k]+mp[k][j]){
mp[i][j]=mp[i][k]+mp[k][j];
}
}
}
}
还有三种最短路的算法现在还未完全掌握,就先不写了。
初学者比较菜。如果有错误欢迎指出~~