- 桶排序
#include <bits/stdc++.h>
using namespace std;
int num[]={0,4,5,9,14,2,18,6,7,8,4,16,1,19,11,17,2,15,10,9,17,5,6,3,20,0,12,4,16,13,8};//下标0~30 ,范围0~20
int bucket[21];//0~20的桶子
int main()
{
int i,j;
for(i=0;i<=30;i++)
bucket[num[i]]++;
for(i=0;i<=20;i++)
{
for(j=bucket[i];j!=0;j--)
cout<<i<<" ";
}
}
- 冒泡排序
#include <bits/stdc++.h>
using namespace std;
int num[]={0,4,5,9,14,2,18,6,7,8,4,16,1,19,11,17,2,15,10,9,17,5,6,3,20,0,12,4,16,13,8};//下标0~30 ,范围0~20
void print()
{
for(int i=1;i<31;i++)
cout<<num[i]<<" ";
}
int main()
{
int i,j,flag=1;//记录有没有交换过,没有直接返回
for(i=1;i<30;i++)//交换趟数
{
for(j=1;j<=30-i;j++)//交换元素下标
if(num[j]>num[j+1])
{
swap(num[j],num[j+1]);
flag=1;
}
if(!flag)return 0;
}
print();
}
- 快速排序
#include <bits/stdc++.h>
using namespace std;
int num[]={0,4,5,9,14,2,18,6,7,8,4,16,1,19,11,17,2,15,10,9,17,5,6,3,20,0,12,4,16,13,8};//下标0~30 ,范围0~20
void print()
{
for(int i=1;i<31;i++)
cout<<num[i]<<" ";
}
void quicksort(int l,int r)
{
int p=num[l],m=(l+r)/2,i=l,j=r;
if(l<r)//l==r不需要排序
{
while(j>i)
{
while(num[j]>=p&&j>i)//注意右哨兵先走,越过那些大于等于轴值的数,同时要保证j不会越过i
j--;
num[i]=num[j]; //覆盖
while(num[i]<=p&&i<j)//越过那些小于等于轴值的数,同时要保证i不会越过j
i++;
num[j]=num[i];
}
//此时j与i停留位置相同
num[i]=p;
quicksort(l,i-1);//处理左边
quicksort(i+1,r);//处理右边
}
}
int main()
{
int i,j,flag=1;
quicksort(1,30);
print();
}
- 归并排序
#include <bits/stdc++.h>
using namespace std;
int num[]={0,4,5,9,14,2,18,6,7,8,4,16,1,19,11,17,2,15,10,9,17,5,6,3,20,0,12,4,16,13,8};//下标0~30 ,范围0~20
int array[31];//临时数组
void print()
{
for(int i=1;i<31;i++)
cout<<num[i]<<" ";
}
void mergesort(int l,int r)
{
int p=num[l],m=(l+r)/2,i,j,k;
if(l<r)//l==r不需要排序
{
mergesort(l,m);
mergesort(m+1,r);
//归并排序好的段
for(i=l,j=m+1,k=0;i<=m&&j<=r;k++)//两段都有元素
{
if(num[i]<num[j])
{
array[k]=num[i];
i++;
}
else
{
array[k]=num[j];
j++;
}
}
//如果还有某段有元素,排进去
for(;i<=m;i++,k++)
array[k]=num[i];
for(;j<=r;j++,k++)
array[k]=num[j];
//将array的值复制过去,注意偏置
for(i=l;i<=r;i++)
num[i]=array[i-l];
}
}
int main()
{
int i,j,flag=1;
mergesort(1,30);
print();
}
- 小哼买书——对数据去重再排序
方法一:用set,正好满足去重又能排序
#include <bits/stdc++.h>
using namespace std;
int num[]={0,4,5,9,14,2,18,6,7,8,4,16,1,19,11,17,2,15,10,9,17,5,6,3,20,0,12,4,16,13,8};//下标0~30 ,范围0~20
int main()
{
int i;
set<int> book;
for(i=1;i<=30;i++)
book.insert(num[i]);
set<int>::iterator p;
for(p=book.begin();p!=book.end();p++)
cout<<*p<<" ";
}
方法二:用改版桶排
#include <bits/stdc++.h>
using namespace std;
int num[]={0,4,5,9,14,2,18,6,7,8,4,16,1,19,11,17,2,15,10,9,17,5,6,3,20,0,12,4,16,13,8};//下标0~30 ,范围0~20
bool bucket[22];
int main()
{
int i;
for(i=1;i<=30;i++)
bucket[num[i]]=1;
for(i=0;i<=20;i++)
if(bucket[i])
cout<<i<<" ";
}
- 链表建立
#include <bits/stdc++.h>
using namespace std;
struct node
{
int value;
node* next;
};
int main()
{
int i,num=0;
node* p,*head=NULL,*q;
while(num!=-1)//输入建表数据,以-1结束
{
cin>>num;
q=new(node);//申请空间
q->value=num;//给新结点赋值
q->next=NULL;//新节点的下一个结点为空 这个不能丢
if(head==NULL)head=q;//空链表
else p->next=q;//非空链表
p=q;//p指向当前结点
}
p=head;
while(p!=NULL)
{
cout<<p->value<<" ";
p=p->next;
}
}
- 炸弹人
输入#代表墙,G代表敌人,.代表空地。炸弹可以从放置点上下左右四个方向延伸,消灭空格上的敌人,遇到墙停止。计算炸弹放置在哪里才能消灭最多的敌人。
输入:
13 13
#############
#GG.GGG#GGG.#
###.#G#G#G#G#
#…#…G#
#G#.###.#G#G#
#GG.GGG.#.GG#
#G#.#G#.#.###
##G…G…#
#G#.#G###.#G#
#…G#GGG.GG#
#G#.#G#G#.#G#
#GG.GGG#G.GG#
#############
输出: 9,9 消灭8个敌人
#include <bits/stdc++.h>
#define maxsize 33
using namespace std;
char a[maxsize][maxsize];
int max1=0,maxx,maxy;
int m,n;//行列
int d[4][2]={{1,0},{-1,0},{0,1},{0,-1}};//方向向量
bool valid(int x,int y)//判断合法位置
{
return x>=1&&x<=m&&y>=1&&y<=n&&a[x][y]!='#';
}
int count(int x,int y)//统计某点消灭的敌人数
{
int i,j,k,sum=0;
for(i=0;i<4;i++)//4个方向
{
j=x,k=y;//不能直接用x,y,因为会改变x,y,那么下一个方向就用不了了
while(valid(j,k)) //不撞墙,不出界
{
if(a[j][k]=='G')sum++;
j+=d[i][0];
k+=d[i][1];
}
}
return sum;
}
int main()
{
int i,j;
cin>>m>>n;
for(i=1;i<=m;i++)
for(j=1;j<=n;j++)
cin>>a[i][j];//输入
for(i=1;i<=m;i++)
for(j=1;j<=n;j++)
if(a[i][j]=='.'&&count(i,j)>max1)//是空地,而且有最大值
{
max1=count(i,j);//更新
maxx=i;
maxy=j;
}
cout<<maxx<<","<<maxy<<" "<<max1;
}
- 火柴棍等式
枚举。对于这种等式枚举,只需枚举前两个加数就能算出和,因此只需两层而不是三层循环。计算出摆0~9需要的火柴数分别为6,2,5,5,4,5,6,3,7,6
由于m最多为24,还要留出4根来摆出加号和等号,因此用来摆数字的火柴个数最多为20根。这20根可以摆出10个1,由于三个位置有数字,因此前两个加数最多有4位,摆成4位+2位=4位的形式。这种形式只有1111+11=1111这个等式,不成立。也就是说只需枚举三位。
#include <bits/stdc++.h>
using namespace std;
int use[10]={6,2,5,5,4,5,6,3,7,6};//摆0~9需要的火柴
int n,sum=0;
int count(int x)//计算摆数x需要的火柴数
{
int ans=0;
if(x==0)return 6;//注意如果是0,直接返回6,否则不会加入下面的循环,会返回0
while(x!=0)
{
ans+=use[x%10];
x=x/10;
}
return ans;
}
int main()
{
int i,j;
cin>>n;
for(i=0;i<1000;i++)
for(j=0;j<1000;j++)
if(n-4==count(i)+count(j)+count(i+j))
{
sum++;
cout<<i<<"+"<<j<<"="<<i+j<<endl;
}
cout<<sum;
}
- 数的全排列
这是个重要的问题。数的全排列可以用递归来实现,假设有数1 2 3 4
设一个递归函数dfs,需要一个参数x来确定当前dfs函数应该处理哪个数。函数在所有可用的数里面找,将其放在第x位,然后dfs(x+1)会处理好后面的全排列。这里递归函数加dfs,并不是一个巧合,实际上这也是一个深度优先搜索问题,即将1 2 3 4四个结点建立完全图,求图的路径数。
#include <bits/stdc++.h>
using namespace std;
int n;//数1~n的全排列
int a[20];
bool book[20];
void dfs(int x)//x:当前应该处理第几个数
{
int i,j;
if(x==n+1)//该打印了
{
for(i=1;i<=n;i++)
cout<<a[i]<<" ";
cout<<endl;
}
//这里有两种方法,一种是使用一个数组记录哪些数字被用过,即被加入了集合,一种是直接找已经建好的集合,看看里面有木有这个数
/* for(i=1;i<=n;i++)//依次1~n试试能不能将数放在第x位
{
if(book[i]==0)
{
a[x]=i;
book[i]=1;
dfs(x+1);
book[i]=0;
}
} */
for(i=1;i<=n;i++)
{
bool ok=1;
for(j=1;j<x;j++)
if(a[j]==i)ok=0;
if(ok)
{
a[x]=i;
dfs(x+1);
}
}
}
//这个dfs函数的返回值其实是一个数组。由于没法直接用return返回数组,故可以采取引用的方法,将
int main()
{
cin>>n;
dfs(1);
}
调用STL中的next_permutation函数
#include <bits/stdc++.h>
using namespace std;
int main()
{
int n,i,a[22];
cin>>n;
for(i=1;i<=n;i++)
a[i]=i;
sort(a+1,a+n+1);//排最小字典序,当然此例没必要
do
{
for(i=1;i<=n;i++)
cout<<a[i]<<" ";
cout<<endl;
}
while(next_permutation(a+1,a+n+1));//注意参数范围!
}
- 解救小哈 dfs求最短路径
#include <bits/stdc++.h>
#define maxsize 110
using namespace std;
int m,n;//行列
int bx,by,ex,ey;//起点,终点
int min1=9999;//最小初值
int a[maxsize][maxsize];//地图
bool book[maxsize][maxsize];//标记
int d[4][2]={{0,1},{0,-1},{1,0},{-1,0}};//方向向量
bool valid(int x,int y)//判断有效函数
{
return book[x][y]==0&&x>=1&&x<=m&&y>=1&&y<=n&&a[x][y]==0;
}
void dfs(int x,int y,int step)//带step的dfs
{
for(int i=0;i<4;i++)
{
int j=x,k=y;//注意一定要循环内定义,保证每次循环都是x,y且不能改变x和y的值
j+=d[i][0];
k+=d[i][1];
if(j==ex&&k==ey)//找到终点,更新min1
{
min1=min(min1,step+1);
return;
}
if(valid(j,k))
{
book[j][k]=1;
dfs(j,k,step+1);
book[j][k]=0;//注意这个取消不能丢,因为要找到最优,一条路需要走多次
}
}
}
int main()
{
int i,j;
cin>>m>>n;
for(i=1;i<=m;i++)
for(j=1;j<=n;j++)
cin>>a[i][j];
cin>>bx>>by>>ex>>ey;
dfs(bx,by,0);
cout<<min1;
}
- 解救小哈 bfs求最短路径
#include <bits/stdc++.h>
#define maxsize 110
using namespace std;
int m,n;//行列
int bx,by,ex,ey;//起点,终点
int a[maxsize][maxsize];//地图
bool book[maxsize][maxsize];//标记
int d[4][2]={{0,1},{0,-1},{1,0},{-1,0}};//方向向量
struct pos
{
int x,y;
int step;//记录了走到每个点走的步数
};
bool valid(int x,int y)//判断有效函数
{
return a[x][y]==0&&book[x][y]==0&&x>=1&&x<=m&&y>=1&&y<=n;
}
int main()
{
int i,j;
queue<pos> q;
pos p;
cin>>m>>n;
for(i=1;i<=m;i++)
for(j=1;j<=n;j++)
cin>>a[i][j];
cin>>p.x>>p.y>>ex>>ey;
p.step=0;//起始点的step为0
q.push(p);
book[1][1]=1;
while(!q.empty())
{
pos temp=q.front();//记录队首元素
if(temp.x==ex&&temp.y==ey)
{
cout<<temp.step;
return 0;
}
q.pop();//队首出队,即走这个点
for(i=0;i<4;i++)
{
j=temp.x+d[i][0];//注意记录
k=temp.y+d[i][1];
if(valid(j,k))
{
p.x=j;
p.y=k;
p.step=temp.step+1;//下一个点的步数等于当前步数加一
q.push(p);
book[j][k]=1;
}
}
}
}
- 宝岛探险
#include<bits/stdc++.h>
#define maxsize 110
using namespace std;
int m,n;
int a[maxsize][maxsize];
bool book[maxsize][maxsize];
int bx,by;
int s=0;
int d[4][2]={{1,0},{-1,0},{0,1},{0,-1}};
void dfs(int x,int y)
{
int i,j,k;
for(i=0;i<4;i++)
{
j=x+d[i][0];
k=y+d[i][1];
if(j>=1&&j<=m&&k>=1&&k<=n&&book[j][k]==0&&a[j][k]!=0)
{
book[j][k]=1;//不用取消标记
s++;//面积加一
dfs(j,k);
}
}
}
int main()
{
int i,j;
cin>>m>>n>>bx>>by;
for(i=1;i<=m;i++)
for(j=1;j<=n;j++)
cin>>a[i][j];
dfs(bx,by);
cout<<s;
}
- 宝岛探险改版:求总岛数
#include<bits/stdc++.h>
#define maxsize 110
using namespace std;
int m,n;
int a[maxsize][maxsize];
int book[maxsize][maxsize];
int color=0;//color的个数代表独立的岛数
int d[4][2]={{1,0},{-1,0},{0,1},{0,-1}};
void dfs(int x,int y,int num)
{
int i,j,k;
for(i=0;i<4;i++)
{
j=x+d[i][0];
k=y+d[i][1];
if(j>=1&&j<=m&&k>=1&&k<=n&&book[j][k]==0&&a[j][k]!=0)
{
book[j][k]=color;//所有能联通的岛都用color标记
dfs(j,k,num);
}
}
}
int main()
{
int i,j;
cin>>m>>n;
for(i=1;i<=m;i++)
for(j=1;j<=n;j++)
cin>>a[i][j];
for(i=1;i<=m;i++)
for(j=1;j<=n;j++)
{
if(!book[i][j]&&a[i][j]!=0)
{
color++;//有未访问过的岛,color+1
dfs(i,j,color);//用color染色
}
}
cout<<color;
}
- 水管工游戏
5 4
5 3 5 3
1 5 3 0
2 3 5 1
6 1 1 5
1 5 5 4
#include<bits/stdc++.h>
#define maxsize 110
using namespace std;
int m,n;
int a[maxsize][maxsize];
int book[maxsize][maxsize];
int d[5][2]={{0,0},{0,1},{1,0},{0,-1},{-1,0}};//右,下,左 ,上
int rx[maxsize],ry[maxsize];
bool flag=0;
void dfs(int x,int y,int out,int s)
{
int i;
// cout<<x<<" "<<y<<" "<<out<<" "<<s<<endl;
if(x==m&&y==n)
{
if(out==1&&(a[x][y]==5||a[x][y]==6))flag=1;
else if(out==2&&(a[x][y]>=1&&a[x][y]<=4))flag=1;
if(flag)
{
for(i=0;i<s;i++)
cout<<rx[i]<<" "<<ry[i]<<endl;
}
return;
}
if(a[x][y]==5||a[x][y]==6)
{
int j=x+d[out][0],k=y+d[out][1];
if(book[j][k]==0&&j>=1&&j<=m&&k>=1&&k<=n)
{
rx[s]=j;
ry[s]=k;
book[j][k]=1;
dfs(j,k,out,s+1);
book[j][k]=1;
}
}
if(a[x][y]>=1&&a[x][y]<=4)
{
for(i=1;i<=4;i++)
{
if(i==out%4+1||i==(out+2)%4+1)
{
int j=x+d[i][0],k=y+d[i][1];
if(book[j][k]==0&&j>=1&&j<=m&&k>=1&&k<=n)
{
rx[s]=j;
ry[s]=k;
book[j][k]=1;
dfs(j,k,i,s+1);
book[j][k]=0;
}
}
}
}
}
int main()
{
int i,j;
cin>>m>>n;
for(i=1;i<=m;i++)
for(j=1;j<=n;j++)
cin>>a[i][j];
rx[0]=1;
ry[0]=1;
dfs(1,1,1,1);
if(!flag)cout<<"impossible";
}
- 图的宽度优先搜索
输入:顶点数,边数,各边起点终点
5 5
1 2
1 3
1 5
2 4
输出:1 2 3 5 4
#include<bits/stdc++.h>
using namespace std;
int m,n;//m点n边
int a[110][110];//邻接矩阵
bool book[110];
int main()
{
int i,j,k;
queue<int> q;
cin>>m>>n;
for(i=1;i<=n;i++)
{
cin>>j>>k;
a[j][k]=1;
a[k][j]=1;
}
q.push(1);
book[1]=1;
while(!q.empty())
{
int temp=q.front();
q.pop();
cout<<temp<<" ";
for(i=1;i<=m;i++)
{
if(book[i]==0&&a[temp][i]==1)
{
q.push(i);
book[i]=1;
}
}
}
}
- 图的深度优先搜索求最小生成树
输入:顶点数,边数,各边起点终点,权值
5 8
1 2 2
1 5 10
2 3 3
2 5 7
3 1 4
3 4 4
4 5 5
5 3 3
输出:9
搜索所有路径,选择权值最小的即可
#include<bits/stdc++.h>
using namespace std;
int m,n;//m点n边
int a[110][110];//邻接矩阵
int min1=99999999;
bool book[110];
void dfs(int x,int s)
{
int i;
if(x==m)
{
min1=min(min1,s);
return;
}
for(i=1;i<=m;i++)
{
if(book[i]==0&&a[x][i]!=0)
{
book[i]=1;
// cout<<i<<" "<<s<<" "<<a[x][i]<<endl;
dfs(i,s+a[x][i]);
book[i]=0;
}
}
}
int main()
{
int i,j,k,l;
cin>>m>>n;//点数 边数
for(i=1;i<=n;i++)//输入起点 终点 权值
{
cin>>j>>k>>l;
a[j][k]=l;
}
book[1]=1;
dfs(1,0);
cout<<min1;
}
- 图的广度优先搜索求最小转机次数
输入: 顶点数 边数 起点 终点
5 7
1 2
1 3
2 3
2 4
3 4
3 5
4 5
输出:2
#include<bits/stdc++.h>
using namespace std;
int m,n;//m点n边
int a[110][110];//邻接矩阵
bool book[110];
int change[110];//记录转机次数的数组
int main()
{
int i,j,k;
cin>>m>>n;//点数 边数
queue<int> q;
for(i=1;i<=n;i++)//输入起点 终点 权值
{
cin>>j>>k;
a[j][k]=1;
a[k][j]=1;
}
book[1]=1;
q.push(1);
while(!q.empty())
{
int temp=q.front(),i;
q.pop();
if(temp==m)
{
cout<<change[temp];
return 0;
}
for(i=1;i<=m;i++)
{
if(book[i]==0&&a[temp][i]==1)
{
book[i]=1;
change[i]=change[temp]+1;
q.push(i);
}
}
}
}
- Floyd算法
4 8
1 2 2
1 3 6
1 4 4
2 3 3
3 1 7
3 4 1
4 1 5
4 3 12
#include<bits/stdc++.h>
#define inf 9999999
using namespace std;
int m,n;//m点n边
int a[110][110];//邻接矩阵
bool book[110];
int dist[110][110];//最短距离矩阵
int main()
{
int i,j,k,l;
cin>>m>>n;//点数 边数
for(i=1;i<=m;i++)
for(j=1;j<=m;j++)
a[i][j]=(i==j?0:inf);
for(i=1;i<=n;i++)//输入起点 终点 权值
{
cin>>j>>k>>l;
a[j][k]=l;
}
for(i=1;i<=m;i++)//1~i编号的点为可用
for(j=1;j<=m;j++)
for(k=1;k<=m;k++)
if(a[j][k]>a[j][i]+a[i][k])a[j][k]=a[j][i]+a[i][k];//用边代表距离矩阵
for(i=1;i<=m;i++)
{
for(j=1;j<=m;j++)
cout<<a[i][j]<<" ";
cout<<endl;
}
}
- Dijkstra算法
#include<bits/stdc++.h>
#define inf 9999999
using namespace std;
int m,n;//m点n边
int a[110][110];//邻接矩阵
bool book[110];
int dist[110];//最短路径数组
int mini()//找当前dist最小值
{
int min=99999999,num;
for(int i=1;i<=m;i++)
{//找v0集合中dist值最小的
if(book[i]==0&&dist[i]<min)
{
min=dist[i];
num=i;
}
}
book[num]=1;
return num;
}
int main()
{
int i,j,k,l;
cin>>m>>n;//点数 边数
for(i=1;i<=m;i++)
for(j=1;j<=m;j++)
a[i][j]=(i==j?0:inf);
for(i=1;i<=n;i++)//输入起点 终点 权值
{
cin>>j>>k>>l;
a[j][k]=l;
}
for(i=1;i<=m;i++)
dist[i]=a[1][i];//最初的dist数组
book[1]=1;
for(i=2;i<=m;i++)//依次计算2~m的dist值
{
int temp=mini();
for(j=2;j<=m;j++)
if(dist[j]>dist[temp]+a[temp][j])dist[j]=dist[temp]+a[temp][j];
}
for(i=1;i<=m;i++)
cout<<dist[i]<<" ";
}
- 解决负权边的Bellman-Ford算法
#include<bits/stdc++.h>
#define inf 9999999
using namespace std;
int m,n;//m点n边
int u[110],v[110],w[110];//邻接矩阵
int dist[110];//最短路径数组
int main()
{
int i,j,k,l;
cin>>m>>n;//点数 边数
for(i=1;i<=n;i++)//输入起点 终点 权值
cin>>u[i]>>v[i]>>w[i];
for(i=1;i<=m;i++)
dist[i]=inf;
dist[1]=0;
for(i=2;i<=m;i++)//m-1次循环
{
for(j=1;j<=n;j++)
if(dist[v[j]]>dist[u[j]]+w[j])dist[v[j]]=dist[u[j]]+w[j];//看看有没有利用这条边??
}
for(i=1;i<=m;i++)
cout<<dist[i]<<" ";
}