十三届蓝桥杯模板总结

dfs_1:

//迷宫问题
#include<iostream>
#include<string>
using namespace std;
int n,m;
string maze[110];
bool vis[110][110];

int  dir[4][2]={{-1,0},{0,-1},{1,0},{0,1}};//移动坐标 
//建议按照 逆时针 (或顺时针)方向写,方便做转头操作 

bool in(int x,int y){
	return 0<=x && x<n && 0<=y && y<m;
}

bool dfs(int x,int y){
	//找到重点 
	if(maze[x][y]=='T'){
		return true;
	}
	
	vis[x][y]=1;//走过了 
	maze[x][y]='+';//标记为+
	
	for(int i=0;i<4;i++){
		int tx=x+dir[i][0];
		int ty=y+dir[i][1];
		if(in(tx,ty)&&maze[tx][ty]!='*'&&!vis[tx][ty]){
			if(dfs(tx,ty)){
				return true;	
			}
		}
	} 
	//走不通,取消标记
	vis[x][y]=0;
	maze[x][y]='.';
	return false; 
}


int main(){
	
	//输入迷宫地图 
	cin>>n>>m;
	for(int i=0;i<n;i++){
		cin>>maze[i];
	} 
	//寻找起始点 
	int x,y;
	for(int i=0;i<n;i++){
		for(int j=0;j<m;j++){
			if(maze[i][j]=='S'){
				x=i,y=j;
			}
		}
	}
	//打印地图 
	if(dfs(x,y)){
		for(int i=0;i<n;i++){
			cout<<maze[i]<<endl;
		}
	} else {
		cout<<"No!"<<endl;
	}
	
	
	return 0;
} 

//
------------------------
//中国象棋 
#include<iostream>
using namespace std;
char maze[15][15];//地图
int dir[8][2]={{-2,-1},{-1,-2},{1,-2},{2,-1},{2,1},{1,2},{-1,2},{-2,1}};//方向
bool vis[15][15];//标记是否走过
bool in(int x,int y){
    return 0<=x&&x<10&&0<=y&&y<9;
}

bool dfs(int x,int y){
    if(maze[x][y]=='T'){
        return true;
    }
    vis[x][y]=true;
    for(int i=0;i<8;i++){
        int tx=x+dir[i][0];
        int ty=y+dir[i][1];
        if(maze[tx][ty]!='#' && in(tx,ty) && !vis[tx][ty]){
            if(dfs(tx,ty)){
                return true;
            }            
        }       
    }
//    vis[x][y]=false;这里我们如果不取消标记反而可以提高代码的运行效率。
//因为我们这里只需要判断两个点是否可达,到达过的状态就没有必要再次到达了。
    return false;
}
int main(){
    for(int i=0;i<10;i++){
        cin>>maze[i];
    }
    int x,y;
    for(int i=0;i<10;i++){
        for(int j=0;j<9;j++){
            if(maze[i][j]=='S'){
                x=i;
                y=j;
            }
        }
    }
  //  dfs(x,y)
    if(dfs(x,y)){
        cout<<"Yes"<<endl;
    }else{
        cout<<"No"<<endl;
    }
    
    return 0;
}
---------------------------------------- 
//迷宫最短路径 
#include <iostream>
using namespace std;
int n,m,x,y;
int ans=1000000;
char maze[100][100];
bool vis[100][100];
int dir[4][2]={{-1,0},{0,1},{1,0},{0,-1}};
bool in(int x,int y){
    return x>=0&&x<n&&y>=0&&y<m;
}
void dfs(int x,int y,int step){
    if(maze[x][y]=='T'){
        if(step<ans){
            ans=step;
        }
        return;
    }
    vis[x][y]=1;
    for(int i=0;i<4;i++){
        int tx=x+dir[i][0];
        int ty=y+dir[i][1];
        if(in(tx,ty)&&maze[tx][ty]!='*'&&!vis[tx][ty]){
            dfs(tx,ty,step+1);
        }
    }
    vis[x][y]=0;

}
int main()
{
    cin>>n>>m;
    for(int i=0;i<n;i++){
        for(int j=0;j<m;j++){
            cin>>maze[i][j];
        }
    }
    for(int i=0;i<n;i++){
        for(int j=0;j<m;j++){
            if(maze[i][j]=='S'){
                x=i;
                y=j;
            }
        }
    }
    dfs(x,y,0);
    cout<<ans<<endl;
} // namespace std;

-------------------------
//踏青 
用 # 表示草地,用 . 表示空地
若相连的#表示为同一块草地,问共有几块
输入:
	地图
输出:
	草地块数
例子:
5 6
.#....
..#...
..#...
...##.
..#...
结果:4	 
*/
#include<iostream>
using namespace std;
char mp[105][105];
bool vis[105][105];
int n,m;
void dfs(int x,int y){
	//不符合条件 
	if(x<0 || x>=n || y<0 || y>=m || vis[x][y] || mp[x][y]=='.' ){
		return ;
	}	
	vis[x][y]=true; 
	dfs(x-1,y);
	dfs(x+1,y);
	dfs(x,y-1);
	dfs(x,y+1);
	
}
int main(){
	cin>>n>>m;
	int cnt=0;
	for(int i=0;i<n;i++){
		for(int j=0;j<m;j++){
			cin>>mp[i][j];
		}
	}
	
	for(int i=0;i<n;i++){
		for(int j=0;j<n;j++){
			if(!vis[i][j] && mp[i][j]=='#'){
				cnt++;
				dfs(i,j);
				cout<<i<<j<<endl; 
			}
		}
	}
	
	cout<<cnt<<endl;
	
	return 0;
} 
-----------------
//迷宫方案数 
#include <iostream>
using namespace std;
int n,m,x,y,ans;
char maze[100][100];
bool vis[100][100];
int dir[4][2]={{-1,0},{0,1},{1,0},{0,-1}};
bool in(int x,int y){
    return x>=0&&x<n&&y>=0&&y<m;
}
void dfs(int x,int y){
  if(maze[x][y]=='e'){
    ans++;
    return;
  }
  vis[x][y]=1;
  for(int i=0;i<4;i++){
    int tx=x+dir[i][0];
    int ty=y+dir[i][1];
    if(in(tx,ty)&&maze[tx][ty]!='#'&&!vis[tx][ty]){
      dfs(tx,ty);
    }
  }
  vis[x][y]=0;
}
int main(){
    cin>>n>>m;
    for(int i=0;i<n;i++){
      for(int j=0;j<m;j++){
        cin>>maze[i][j];
      }
    }
    for(int i=0;i<n;i++){
      for(int j=0;j<m;j++){
        if(maze[i][j]=='s'){
          x=i,y=j;
        }
      }
    }
    dfs(x,y);
    cout<<ans<<endl;
    return 0;
}

----------------------------------
//最大蛋糕 
#include <iostream>
using namespace std;
int n,m,cnt,ans;
char maze[100][100];
bool vis[100][100];
int dir[4][2]={{-1,0},{0,1},{1,0},{0,-1}};
bool in (int x,int y){
  return x<n&&x>=0&&y<m&&y>=0;
}
void dfs(int x,int y){
    if(x<0||x>=n||y<0||y>=n||vis[x][y]||maze[x][y]=='.'){
        return;
    }
  vis[x][y]=1;
  cnt++;
  for(int i=0;i<4;i++){
    int tx=x+dir[i][0];
    int ty=y+dir[i][1];
    if(in(tx,ty)&&maze[tx][ty]=='#'&&!vis[tx][ty]){
      dfs(tx,ty);
    }
  }
}
int main()
{
  cin>>n>>m;
  for(int i=0;i<n;i++){
    for(int j=0;j<m;j++){
      cin>>maze[i][j];
    }
  }
  for(int i=0;i<n;i++){
    for(int j=0;j<m;j++){
      if(!vis[i][j]&&maze[i][j]=='#'){//没有访问过!!并且是#
        cnt=0;
        dfs(i,j);
        if(cnt>ans){
          ans=cnt;
        }
      }
    }
  }
  cout<<ans<<endl;
} // namespace std;
-------------------
//家谱 
#include<iostream>
#include<vector>
using namespace std;

vector<int> son[100005];//记录
bool f[100005];//为了确定根
int ans[100005];//答案数组

int dfs(int u) {//计算这一代的人数
	int ret=0;
	//先统计包括自己的后代
	for(int i=0; i<son[u].size(); i++) {
		ret+=dfs(son[u][i]);
	}
	ans[u]=ret;
	return ret+1;//int型返回值代表这一代的人数
}


int main() {
	int x,y,n,u;
	cin>>n;
	for(int i=0; i<n-1; i++) {
		cin>>x>>y;
		son[x].push_back(y);
		f[y]=true;
	}

	for(int i=1; i<=n; i++) {
		if(!f[i]) {
			u=i;//u代表根节点
			break;
		}
	}

	dfs(u);//传入根节点
	for(int i=1; i<=n; i++) {
		cout<<ans[i]<<endl;
	}

	return 0;
}
--------------------
//马的覆盖点 
#include<iostream>
using namespace std;
/*马可以走到哪里
输入棋盘的大小 nXm 输入马的起始位置 (x,y)
输出马三步以内可以到达的位置,用 # 表示 
*/
int n,m;
char mp[105][105];
bool vis[105][105];
int a[8][2]= {{1,2},{1,-2},{-1,2},{-1,-2},{2,1},{-2,1},{2,-1},{-2,-1}};

void dfs(int x,int y,int step) {

	if(x<0 || x>=n || y<0 || y>=m ) {
		return ;
	}


	if(step >3) {
		return ;
	}

	mp[x][y]='#';

	for(int i=0; i<8; i++) {
		dfs(x+a[i][0],y+a[i][1],step+1);
		//step++ (X) ++step(X) ? 
	}

}


int main() {
	cin>>n>>m;
	for(int i=0; i<n; i++) {
		for(int j=0; j<m; j++) {
			mp[i][j]='.';
		}
	}

	int x,y;
	cin>>x>>y;
	mp[x][y]='B';
	dfs(x-1,y-1,0);

	for(int i=0; i<n; i++) {
		for(int j=0; j<m; j++) {
			cout<<mp[i][j];
		}
		cout<<endl;
	}

	return 0;
}
------------------
#include<bits/stdc++.h>
#define ll long long
#define N 100010
using namespace std;
const ll maxn = 1e2 + 5;
//ll a[maxn],b[maxn];
//bool vis[maxn];
int ans[maxn];
vector<int>v[maxn];
int n, m;
bool vis[maxn][maxn][2];
bool flag;
char a[maxn][maxn];
void dfs(int x,int y,int d)
{
    if(x>=n||x<0||y>=m||y<0||vis[x][y][d]||a[x][y]=='#')
        return ;
    vis[x][y][d]=true;
    dfs(x+(2-d),y,d);
    dfs(x-(2-d),y,d);
    dfs(x,y+(2-d),d);
    dfs(x,y-(2-d),d);
    return;
}
int main() {
    int x, y, tx, ty;
    cin >> n >> m;
    for(int i = 0; i < n; i++)
        cin >> a[i];
    for(int i = 0; i < n; i++)
        for(int j = 0; j < m; j++)
            if(a[i][j] == 'w') {
                x = i;
                y = j;
            } else if(a[i][j] == 'g') {
                tx = i;
                ty = j;
            }
            bool flag=false;
    dfs(x, y, 0);
    dfs(tx, ty, 1);
    for(int i = 0; i < n; i++)
        for(int j = 0; j < m; j++)
            if(vis[i][j][0]&&vis[i][j][1])
                flag=true;
                if(flag)
                    cout<<"yes"<<endl;
                else cout<<"no"<<endl;
            return 0;
}
------------------
//蒜头军开公司 
#include<iostream>
using namespace std;
int task[15][15];
int vis[15];
int n;
int ans = 9999999;
void dfs(int step, int t)
{
	if (step == n)
	{
		ans = min(ans, t);
		return;
	}
	for (int i = 0; i < n; i++)
	{
		if (!vis[i])
		{
			vis[i] = 1;
			dfs(step + 1, t + task[step][i]);
			vis[i] = 0;
		}
	}
}
int main()
{
	cin >> n;
	for (int i = 0; i < n; i++)
	{
		for (int j = 0; j < n; j++)
		{
			cin >> task[i][j];
		}
	}
	dfs(0, 0);
	cout << ans <<endl;
	return 0;
}
----------------


dfs_2:

#include<iostream>
using namespace std;
int n,k,sum,ans;
int a[100];

void dfs(int i,int cnt,int s){
	if(i==n){
		if(cnt==k && s==sum){
			ans++;
		}
		return ;
	}
	dfs(i+1,cnt,s);//不选 a[i] 
	dfs(i+1,cnt+1,s+a[i]);//选 a[i] 
}

int main(){
	cin>>n>>k>>sum;
	for(int i=0;i<n;i++){
		cin>>a[i];
	}
	ans=0;
	dfs(0,0,0);
	cout<<ans<<endl;
	return 0;
}
/*
输入:
5 3 9
1 2 3 4 5
输出: 
2 
*/
---------------
#include<iostream>
using namespace std;

int n,k,sum,ans,a[110];
bool xuan[110];//标记每个数是否被选
void dfs(int s,int cnt) {
	if(cnt==k && s==sum)  {
		ans++;
	}
	for(int i=0; i<n; i++) {
		if(!xuan[i]) {
			xuan[i]=true;
			dfs(s+a[i],cnt+1);
			xuan[i]=false;
		}


	}
}


int main() {

	cin>>n>>k>>sum;
	for(int i=0; i<n; i++) {
		cin>>a[i];
	}
	ans=0;
	dfs(0,0);

	cout<<ans<<endl;

	return 0;
}
/*
输入:5 3 9
	 1 2 3 4 5
输出:12 (错误) 
原因:系统把 2 3 5 , 2 5 3 ,3 2 5...当成不同的选择
改正:除以 k 的阶乘
  
	int k2=1; 
	
	for(int i=1;i<=k;i++){
		k2*=i;
	}

	cout<<ans/k2<<endl;  
*/


------------------------
/*现在给定n根木棍,现在问用这些木棍能不能拼成一个等边三角形(要求这些木棍全部用到)*/
#include<iostream>
using namespace std;

int n,sum=0;
int l[105];

bool dfs(int a,int b,int c,int i){//i代表选的根数 
	
	//cout<<"a "<<a<<" b "<<b<<" c "<<c<<" i "<<i<<endl; 
	if(a==b && a==c && i==n){
		//cout<<"yes"<<endl;
		return true;
	} 
	
	if(a>sum/3 || b>sum/3 || c>sum/3){
		return false;
	}
	
	bool a1=dfs(a+l[i],b,c,i+1);
	bool a2=dfs(a,b+l[i],c,i+1);
	bool a3=dfs(a,b,c+l[i],i+1);
	
	if(a1||a2||a3){
		return true;
	} 
	
}


int main(){
	cin>>n;
	for(int i=0;i<n;i++){
		cin>>l[i];
		sum+=l[i];
	}
	
	if(sum%3!=0 ){
		cout<<"no"<<endl;
		return 0;
	}
	
	int a=0,b=0,c=0;//代表每一根的和
	bool d=dfs(a,b,c,0); 
	
	if(d){
		cout<<"yes"<<endl; 
	} else{
		cout<<"no"<<endl; 
	} 
	
	
	return 0;
}
-------------
//八皇后 
#include<iostream>
using namespace std;
int ans=0;
bool col[10],x1[20],x2[20];//列,对角线1,对角线2 
bool check(int r,int i){
	return !col[i] && !x1[r+i] && !x2[r-i+8];
}
void dfs(int r){
	for(int i=0;i<8;i++){//行 
		if(r==8){
			ans++;
			return;
		}
		
		if(check(r,i)){
			col[i]=x1[r+i]=x2[r-i+8]=true;
			//r-i+8 防止负坐标
			dfs(r+1); 
			col[i]=x1[r+i]=x2[r-i+8]=false;
		}
	} 
	
} 

int main(){
	
	dfs(0);
	cout<<ans<<endl;
	return 0;
	
}
/*没有输入,输出 92 
八皇后问题有92组解 
*/
----------------------
//等边三角形 
#include<cstdio>
#include<iostream>
#include<cmath>
using namespace std;
int k[30],p[10],x[10];
int n,M,count,sum=0;
double w,mypow[160][5];
void dfs(int a){
	if(a==0){//当1~n位置已经赋值 
		for(int i=1;i<=n;i++){//循环计算每一组k,x,p
			w=mypow[x[i]][p[i]];
			sum+=(int)w*k[i];
		}
		if(sum==0){
			count++;	
		}
		return ;//循环当前位置的下一个数 
	}
	for(int i=1;i<=M;i++){
		x[a]=i;//给当前位置赋值 
		sum=0;//计算前先将sum清零 
		dfs(a-1);
	}
}
int main(){
	scanf("%d",&n);
	scanf("%d",&M);
	for(int i=1;i<=n;i++){
		scanf("%d",&k[i]);
		scanf("%d",&p[i]);
	}
	for(double i=1;i<=150;i++){//此处用i<=M,内循环用i<=n会有测试数据不通过,?也许是因为测试数据在演我 
		for(double j=1;j<=4;j++){
			mypow[(int)i][(int)j]=pow(i,j);//数组下标必须为整型,并且double=pow[double,double] //用二维数组存储pow结果,如果在递归中用pow计算,会需要大量时间
		}
	}
	dfs(n);
	printf("%d",count);
	return 0;
}

----------------------
//方程的解
#include<cstdio>
#include<iostream>
#include<cmath>
using namespace std;
int k[30],p[10],x[10];
int n,M,count,sum=0;
double w,mypow[160][5];
void dfs(int a){
	if(a==0){//当1~n位置已经赋值 
		for(int i=1;i<=n;i++){//循环计算每一组k,x,p
			w=mypow[x[i]][p[i]];
			sum+=(int)w*k[i];
		}
		if(sum==0){
			count++;	
		}
		return ;//循环当前位置的下一个数 
	}
	for(int i=1;i<=M;i++){
		x[a]=i;//给当前位置赋值 
		sum=0;//计算前先将sum清零 
		dfs(a-1);
	}
}
int main(){
	scanf("%d",&n);
	scanf("%d",&M);
	for(int i=1;i<=n;i++){
		scanf("%d",&k[i]);
		scanf("%d",&p[i]);
	}
	for(double i=1;i<=150;i++){//此处用i<=M,内循环用i<=n会有测试数据不通过,?也许是因为测试数据在演我 
		for(double j=1;j<=4;j++){
			mypow[(int)i][(int)j]=pow(i,j);//数组下标必须为整型,并且double=pow[double,double] //用二维数组存储pow结果,如果在递归中用pow计算,会需要大量时间
		}
	}
	dfs(n);
	printf("%d",count);
	return 0;
}
 

---------------------
//数独 
#include<iostream>
using namespace std;
char s[10][10];
bool f;
bool vx[10][10];//每一行能否填几
bool vy[10][10];
bool vv[10][10];//单个3X3的格子能否填几
void dfs(int x,int y) {
	if(f) {
		return;
	}

	if(x==9) {
		f=true;
		//找到一个后输出
		for(int i=0; i<9; i++) {
			for(int j=0; j<9; j++) {
				cout<<s[i][j]<<" ";
			}
			cout<<endl;
		}
		return ;
	}


	if(y==9 ) {
		dfs(x+1,0);
		return;
	}
	if(s[x][y]!='*') {
		dfs(x,y+1);
		return ;
	}
	for(int i=1; i<=9; i++) {
		if(!vx[x][i] && !vy[y][i] && !vv[x / 3 * 3 + y / 3][i]) {
			s[x][y]='0'+i;
			vx[x][i]=true;
			vy[y][i]=true;
			vv[x/3*3+y/3][i]=true;

			dfs(x,y+1);

			vx[x][i]=false;
			vy[y][i]=false;
			vv[x/3*3+y/3][i]=false;
			s[x][y]='*';
		}
	}


}

int main() {

	for(int i=0; i<9; i++) {
		for(int j=0; j<9; j++) {
			cin>>s[i][j];
		}
	}

	for(int i=0; i<9; i++) {
		for(int j=0; j<9; j++) {
			if(s[i][j]!='*') {
				vx[i][s[i][j]-'0']=true;
				vy[j][s[i][j]-'0']=true;
				vv[i/3*3+j/3][s[i][j]-'0']=true;

			}
		}
	}

	dfs(0,0);

	return 0;
}
-------------------
//2n皇后 
#include<iostream>
using namespace std;

int mp[10][10];
int vy[10],vd1[20],vd2[20];//行,列,对角线1,对角线2
int n;
int ans;

void dfs(int x,int p){
	if(x==n && p==2 ){ //p: 一表示放黑的,二表示方白的,零表示都可以,先放黑后放白 
		ans++;
		return;
	}
	
	if(x==n ){
		dfs(0,p+1);
		return; 
	}


	for(int i=0;i<n;i++){
		if(mp[x][i] && vy[i]!=3 && vy[i]!=p && vd1[x+i]!=3 && 
		vd1[x+i]!=p && vd2[x-i+n]!=3 && vd2[x-i+n]!=p ){
			mp[x][i]=0;
			vy[i]+=p;
			vd1[x+i]+=p;
			vd2[x-i+n]+=p;
			dfs(x+1,p);
			vy[i]-=p;
			vd1[x+i]-=p;
			vd2[x-i+n]-=p;
			mp[x][i]=1;
		}
	}
}

int main(){
	
	cin>>n;
	for(int i=0;i<n;i++){
		for(int j=0;j<n;j++){
			cin>>mp[i][j];
		}
	}
	
	dfs(0,1);
	cout<<ans<<endl;
	
	return 0;
} 


--------------------
//引爆炸弹 
#include<iostream>
using namespace std;
char s[1005][1005];
bool vx[1005],vy[1005];
int n,m,cnt;
void dfs(int x,int y){
	s[x][y]='0';
	if(!vx[x]){
		vx[x]=true;
		for(int i=0;i<m;i++){
			if(s[x][i]=='1'){
				dfs (x,i);
			} 
		}
	}
	if(!vy[y]){
		vy[y]=true;
		for(int i=0;i<n;i++){
			if(s[i][y]=='1'){
			dfs(i,y); 
		}
	}
}
}

int main(){

	cin>>n>>m;
	for(int i=0;i<n;i++){
		for(int j=0;j<m;j++){
			cin>>s[i][j];
		}
	}
	for(int i=0;i<n;i++){
		for(int j=0;j<m;j++){
			if(s[i][j]=='1'){
				cnt++;
				dfs(i,j); 
				
			}
		}
	}	
	
	cout<<cnt<<endl;
	return 0;
} 

/*
样例输入: 
5 5
00010
00010
01001
10001
01000

样例输出: 
2
*/

bfs_1:

---------------
约瑟夫!!! 
#include<iostream>
#include<queue>
using namespace std;

int main() {
	int n,m;
	cin>>n>>m;
	queue<int> q;
	for(int i=1;i<=n;i++){
		q.push(i);
	}
	int cur=1;
	while(q.size()>1){
		int x=q.front();
		q.pop();
		if(cur!=m){
			q.push(x);
			cur++;
		} else{
			cur=1;
		}
	}
	cout<<q.front()<<endl;
}
-----------------------
//迷宫bfs 
#include<iostream>
#include<queue> 
using namespace std;
int n,m;
char maze[105][105];
bool vis[105][105];
int dir[4][2]={{-1,0},{0,-1},{1,0},{0,1}};//方向
bool in(int x,int y){//范围
	return x>=0 && x<n && y>=0 && y<m;
}
//节点
struct node{
	int x,y,d;
	node(int xx,int yy,int dd){
		x=xx;
		y=yy;
		d=dd;
	}
};

int bfs(int sx,int sy){
	queue<node> q;
	q.push(node(sx,sy,0));
	vis[sx][sy]=true;
	while(!q.empty()){
		node now=q.front();
		q.pop();
		for(int i=0;i<4;i++){
			int tx=now.x+dir[i][0];
			int ty=now.y+dir[i][1];
			if(in(tx,ty) && maze[tx][ty]!='*' && !vis[tx][ty]){
				if(maze[tx][ty]=='T'){
					return now.d +1; 
				}else{
					vis[tx][ty]=true;
					q.push(node(tx,ty,now.d+1));
				}
			}
		}
	} 
	return -1;
}

int main(){
	cin>>n>>m;
	for(int i=0;i<n;i++){
		for(int j=0;j<m;j++){
			cin>>maze[i][j];
		}
	}
	
	int x,y;
	for(int i=0;i<n;i++){
		for(int j=0;j<m;j++){
			if(maze[i][j]=='S'){
				x=i;
				y=j;
			}
		}
	}
	
	cout<<bfs(x,y)<<endl; 
	
	return 0;
}

/*
样例输入:
5 6
....S*
.**...
.*..*.
*..**.
.T....

样例输出: 
7
-------------
//一维度坐标
 
/*在长度为【0,n】的一维坐标中,输入A,B的地址,问能否从A到B。
移动方式:向前一步(坐标+1),向后一步(坐标-1),跳(坐标*2)*/
#include<iostream>
#include<queue>
#include<utility>
using namespace std;
bool vis[100];
int main() {
	int n,A,B,now,step;
	cin>>n>>A>>B;

	queue< pair<int,int> >q;
	q.push(make_pair(A,0));
	vis[A]=true;
	while(!q.empty()) {
		
		now=q.front().first;
		step=q.front().second;
		
		q.pop();
		if(now==B){
			cout<<step<<endl;
			break;
		}
		if(now+1<=n && !vis[now+1]) {
			q.push(make_pair(now+1,step+1));
			vis[now+1]=true;
		}
		if(now-1>=0 && !vis[now-1]) {
			q.push(make_pair(now-1,step+1));
			vis[now-1]=true;
		}
		if(now*2<=n && !vis[now*2]) {
			q.push(make_pair(now*2,step+1));
			vis[now*2]=true;
		}
	}


	return 0;
}
/*
样例输入:
10 2 7
样例输出
3
*/
-------------------
//密码锁 
#include<iostream>
#include<queue>
#include<algorithm>
#include<cstring>
using namespace std;

struct node {
	int num[4],step;
} first,last;

int vis[11][11][11][11];

void bfs() {
	int i;
	node a,next;
	queue<node> q;
	a=first;
	a.step=0;
	q.push(a);
	memset(vis,0,sizeof(vis));
	vis[a.num[0]][a.num[1]][a.num[2]][a.num[3]]=1;
	while(!q.empty()) {
		a=q.front();
		q.pop();
		//bfs出口
		if(a.num[0]==last.num[0] && a.num[1]==last.num[1]
		        &&a.num[2]==last.num[2] &&a.num[3]==last.num[3] ) {
			cout<<a.step<<endl;
			return;
		}
		for(int i=0; i<4; i++) { //++1
			next=a;
			next.num[i]++;
			if(next.num[i]==10) {
				next.num[i]=1;
			}
			if(!vis[next.num[0]][next.num[1]][next.num[2]][next.num[3]]) {
			vis[next.num[0]][next.num[1]][next.num[2]][next.num[3]]=1;
				 next.step++;
				 q.push(next);
			}
		}

		for(int i=0; i<4; i++) { //--1
			next=a;
			next.num[i]--;
			if(next.num[i]==0) {
				next.num[i]=9;
			}
			if(!vis[next.num[0]][next.num[1]][next.num[2]][next.num[3]]) {
			vis[next.num[0]][next.num[1]][next.num[2]][next.num[3]]=1;
				 next.step++;
				 q.push(next);
			}
		}

		for(int i=0; i<3; i++) {//交换 
			next=a;
			next.num[i]=a.num[i+1];
			next.num[i+1]=a.num[i];
			if(!vis[next.num[0]][next.num[1]][next.num[2]][next.num[3]]) {
			vis[next.num[0]][next.num[1]][next.num[2]][next.num[3]]=1;
				 next.step++;
				 q.push(next);
			}
		}

	}
}



int main() {
	int i,j,k;
	char s1[10],s2[10];
	cin>>s1>>s2;
	for(int i=0; i<4; i++) {
		first.num[i]=s1[i]-'0';
		last.num[i]=s2[i]-'0';
	}
	bfs();

	return 0;
}

/*
样例输入:
1234
2144
样例输出:
2
*/
-----------------
//乳草的侵占 
#include <iostream>
#include <cstring>
#include <queue>
using namespace std;
struct node{
	int x, y;
	node(){}
	node(int _x, int _y)
	{
		x = _x;
		y = _y;
	}
};

int n, m, u, v;
char mp[110][110];
int vis[110][110];
int dx[] = {1, -1, 0, 0, -1, 1, -1, 1};//8个方向
int dy[] = {0, 0, 1, -1, 1, 1, -1, -1};
int bfs()
{
	vis[u][v] = 1;//标记访问
	queue<node> q;
	q.push(node(u, v));
	int ma = -1;
	while (!q.empty())
	{
		u = q.front().x;
		v = q.front().y;
		q.pop();
		for (int i = 0; i < 8; i++)
		{
			int x = u + dx[i];
			int y = v + dy[i];
			if (x >= 1 && x <= n && y >= 1 && y <= m && mp[x][y] == '.' && !vis[x][y])
			{
				q.push(node(x, y));
				vis[x][y] = vis[u][v] + 1;
				ma = vis[x][y];//记录时间
			}
		}
	}
	return ma - 1;
}

int main()
{
	cin >> m >> n >> v >> u;
	u = n - u + 1;
	for (int i = 1; i <= n; i++)
	{
		for (int j = 1; j <= m; j++)
		{
			cin >> mp[i][j];//输入
		}
	}
	cout << bfs() << endl;
	return 0;
} 

-----------------
//一维跳棋 
 #include<bits/stdc++.h>
using namespace std;
int n;
string s1,s2;
vector<int> temp;
struct Node{
    string s;
    int ind;//空格位置
    vector<int> vc;
};
void bfs(){
    queue<Node> q;
    q.push({s1,n,temp});
    while(!q.empty()){
        Node now=q.front();
        temp=now.vc;
        q.pop();
        if(now.s==s2){//合法结束状态结束搜索
            for(int i=0;i<temp.size();i++){
                cout<<temp[i]+1;
                if((i+1)%5!=0) cout<<" ";
                else cout<<endl;
            }
            break;
        }
        if(now.ind-1>=0){//左边棋子和右边空格交换
            if(now.s[now.ind-1]=='W'){
                Node next=now;
                swap(next.s[now.ind-1],next.s[now.ind]);
                temp.push_back(now.ind-1);
                q.push({next.s,now.ind-1,temp});
                temp.pop_back();
            }
        }
        if(now.ind-2>=0&&now.s[now.ind-1]=='B'&&now.s[now.ind-2]=='W'){//左边棋子跳到右边空格
            Node next=now;
            swap(next.s[now.ind-2],next.s[now.ind]);
            temp.push_back(now.ind-2);
            q.push({next.s,now.ind-2,temp});
            temp.pop_back();
        }
        if(now.ind+1<2*n+1){//右边棋子和左边空格交换
            if(now.s[now.ind+1]=='B'){
                Node next=now;
                swap(next.s[now.ind+1],next.s[now.ind]);
                temp.push_back(now.ind+1);
                q.push({next.s,now.ind+1,temp});
                temp.pop_back();
            }
        }
        if(now.ind+2<2*n&&now.s[now.ind+1]=='W'&&now.s[now.ind+2]=='B'){//右边棋子跳到左边空格
            Node next=now;
            swap(next.s[now.ind+2],next.s[now.ind]);
            temp.push_back(now.ind+2);
            q.push({next.s,now.ind+2,temp});
            temp.pop_back();
        }
    }
}
int main(){
    cin>>n;
    for(int i=0;i<n;i++){
        s1+='W';
        s2+='B';
    }
    s1+=' ';
    s2+=' ';
    for(int i=n+1;i<2*n+1;i++){
        s1+='B';
        s2+='W';
    }
    bfs();
    return 0;
}


------------------
//三阶魔方 
#include<iostream>
#include<map>
#include<queue>
#include<cstdio>
using namespace std;

struct node{
	int a[3][3];
	bool operator < (const node &x) const{
		for(int i=0;i<3;i++){
			for(int j=0;j<3;j++){
				if(a[i][j]<x.a[i][j]){
					return 1;
				}
			}
		}
		return 0;
	}
	
	bool operator == (const node &x) const{
		for(int i=0;i<3;i++){
			for(int j=0;j<3;j++){
				if(a[i][j]!=x.a[i][j]){
					return 0;
				}
			}
		}
		return 1;
	}
	void print(){
		for(int i=0;i<3;i++){
			for(int j=0;j<3;j++){
				cout<<a[i][j]<<" ";
			}
			cout<<endl;
		}
	}
	int tonum(){
		int res=0;
		for(int i=0;i<3;i++){
			for(int j=0;j<3;j++){
				res=res*10+a[i][j];
			}
		}
		return res;
	}
	
} init;

node rotate(node a,int s,int d){
	node res=a;
	if(d==-1){ //right move
		int tmp=res.a[s][2];
		res.a[s][2]=res.a[s][1];
		res.a[s][1]=res.a[s][0];
		res.a[s][0]=tmp;
	}else if(d==1){ // left move
		int tmp=res.a[s][0];
		res.a[s][0]=res.a[s][1];
		res.a[s][1]=res.a[s][2];
		res.a[s][2]=tmp;
	}else if(d==-2){ //up move
		int tmp=res.a[0][s];
		res.a[0][s]=res.a[1][s];
		res.a[1][s]=res.a[2][s];
		res.a[2][s]=tmp;
	} else if(d==2){ // down move
		int tmp=res.a[2][s];
		res.a[2][s]=res.a[1][s];
		res.a[1][s]=res.a[0][s];
		res.a[0][s]=tmp;
	}
	return res;
}

int bfs(node st){
	queue<node> q;
	map<int,int> d;
	q.push(st);
	d[st.tonum()]=0;
	while(!q.empty()){
		node x=q.front();
		q.pop();
		int tt=x.tonum();
		if(x==init){
			return d[x.tonum()];
		}
		node tmp;
		for(int i=0;i<3;i++){
			tmp=rotate(x,i,-1);
			if(!d.count(tmp.tonum())){
				d[tmp.tonum()]=d[tt]+1;
				q.push(tmp);
			}
			tmp=rotate(x,i,1);
			if(!d.count(tmp.tonum())){
				d[tmp.tonum()]=d[tt]+1;
				q.push(tmp);
			}
		}
		for(int i=0;i<3;i++){
			tmp=rotate(x,i,-2);
			if(!d.count(tmp.tonum())){
				d[tmp.tonum()]=d[tt]+1;
				q.push(tmp);
			}
			tmp=rotate(x,i,2);
			if(!d.count(tmp.tonum())){
				d[tmp.tonum()]=d[tt]+1;
				q.push(tmp);
			}
		}
	}
	return -1;
} 


int main(){
	for(int i=0;i<3;i++){
		for(int j=0;j<3;j++){
			init.a[i][j]=i*3+j+1; 
		}
	}
	node t;
	for(int i=0;i<3;i++){
		int n;
		cin>>n;
		t.a[i][2]=n%10;
		n/=10;
		t.a[i][1]=n%10;
		n/=10;
		t.a[i][0]=n;
	}
	int ans=bfs(t);
	cout<<ans<<endl;
	return 0;
}

/*
样例输入:
412
756
389
样例输出: 
2 

*/
------------------
//吃糖时间 
#include<iostream>
#include<queue>
#include<vector>
#include<cstdlib>
using namespace std;

typedef struct{
	int v;
	int step;
}node;

int maxn;
queue<node> q;
vector<int> g[100010];
bool vis[100010];

void bfs(){
	int i;
	node p,t;
	while(!q.empty()){
		p=q.front();
		q.pop();
		for(int i=0;i<g[p.v].size();i++){
			t.v=g[p.v][i];
			t.step=p.step+1;
			if(!vis[t.v]){
				q.push(t);
				vis[t.v]=1;
				if(t.step>maxn){
					maxn=t.step;
				}
			}
		}
	} 
	
	
	
}

int main(){
	node t;
	int n,p,c,m,a,b,i;
	cin>>n>>p>>c;
	cin>>m;
	for(int i=0;i<p;i++){
		cin>>a>>b;
		g[a].push_back(b);
	    g[b].push_back(a);
	}
	t.v=c;
	t.step=1;
	vis[t.v]=1;
	q.push(t);
	bfs();
	cout<<maxn+m<<endl;
	return 0;	
}
/*
样例输入:
4 3 1
2 
1 2
2 3
1 4
样例输出:
5 

*/


递推:

//错排 
#include<iostream>
using namespace std;

const int N=1e3+9;
long long f[N];

int main(){
	
	int n;
	cin>>n;
	//方法一:数组存储 
	f[1]=0,f[2]=1;
	for(int i=3;i<=n;i++){
		f[i]=(f[i-1]+f[i-2])*(i-1);
	}
	cout<<f[n]<<endl;
	
	//方法二:空间优化  
	long long a=0,b=1,c=1;
	for(int i=3;i<=n;i++){
		c=(a+b)*(i-1);
		a=b;
		b=c;
	} 
	if(n!=1){a
		cout<<c<<endl; 
	}else{
		cou<<0<<endl;
	}
} 

-------------------------
//杨辉三角 
#include<iostream>
using namespace std;
int n;
int a[10][10]= {0};

int main() {

	cin>>n;
	a[0][0]=1;
	for(int i=1; i<n; i++) {
		a[i][0]=1;
		for(int j=1; j<n; j++) {
			a[i][j]=a[i-1][j-1]+a[i-1][j];
		}
	}

	for(int i=0; i<n; i++) {
		for(int j=0; j<n; j++) {
			cout<<a[i][j]<<" ";
		}
		cout<<endl;
	}
	
	int m;
	cin>>m;
	cout<<a[n-1][m-1]<<endl;

	return 0;
}
/*
5
1 0 0 0 0
1 1 0 0 0
1 2 1 0 0
1 3 3 1 0
1 4 6 4 1
3
6
*/
------------------
//过河卒 
#include<iostream>
using namespace std;
int dir[8][2]= {{1,2},{1,-2},{2,1},{2,-1},{-1,2},{-1,-2},{-2,1},{-2,-1}};
bool  d[30][30];
long long dp[30][30];
int main() {
	int n,m,cx,cy;// n,m棋盘大小  cx,xy马的位置
	cin>>n>>m>>cx>>cy;
	d[cx][cy]=true;
	for(int i=0; i<8; i++) {
		int tx=cx+dir[i][0];
		int ty=cy+dir[i][1];
		if(tx>=0 && tx<=n && ty>=0 && ty<=n) {
			d[tx][ty]=true;//记录为马控制点
		}
	}

	dp[0][0]=1;//dp[n][m]即为从(0,0)到(n,m)的路径数目
	for(int i=0; i<=n; i++) {
		for(int j=0; j<=m; j++) {
			if(d[i][j]==false) {
				if(i) {
					dp[i][j]+=dp[i-1][j];
				}
				if(j) {
					dp[i][j]+=dp[i][j-1];
				}
			}
		}
	}

	cout<<dp[n][m]<<endl;
	return 0;
}
/*
样例输入:
5 5 2 4
样例输出:
14 
*/
-----------------
//迷宫最短路 dp 版 
/*输入一张地图,求从左上角到右下角的最短路径长,只能往右/下方向移动*/
#include<iostream>
#include<algorithm>
using namespace std;
int a[110][110];
int dp[110][110];
int main(){
	int n;
	cin>>n;
	
	for(int i=1;i<=n;i++){
		for(int j=1;j<=n;j++){
			cin>>a[i][j];
		}
	}
	
	dp[1][1]=0;
	for(int i=1;i<=n;i++){
		for(int j=1;j<=n;j++){
			if(i==1 && j==1){
				continue;
			}else if(i==1){
				dp[i][j]=dp[i][j-1]+a[i][j];
			}else if(j==1){
				dp[i][j]=dp[i-1][j]+a[i][j];
			}else{
				dp[i][j]=min(dp[i-1][j],dp[i][j-1])+a[i][j];
			}
		}
	}
	
	cout<<dp[n][n]<<endl;
	
	return 0;
}
/*
样例输入: 
3
0 3 4
6 2 5
5 4 3
样例输出: 
12
*/
---------
//数字三角形回家 
#include<iostream>
#include<algorithm>
using namespace std;
int n;
int a[105][105]={0};
int dp[105][105]={0};

int main() {

	cin>>n;
	for(int i=1; i<=n; i++) {
		for(int j=1; j<=i; j++) {
			cin>>a[i][j];
		}
	}
	int ans=0;
	for(int i=1; i<=n; i++) {
		for(int j=1; j<=i; j++) {
			dp[i][j]=a[i][j]+max(dp[i-1][j],dp[i-1][j-1]);
			if(i==n){
				ans=max(dp[i][j],ans);
			}
		}
	}

	cout<<ans<<endl;
	cout<<"--输出dp数组--"<<endl;
	for(int i=1; i<=n; i++) {
		for(int j=1; j<=i; j++) {
			cout<<dp[i][j]<<" ";
		}
		cout<<endl;
	}
	return 0;
}

/*
样例输入: 
4
3
1 2
6 2 3
3 5 4 1

样例输出: 
15
--输出dp数组--
3
4 5
10 7 8
13 15 12 9 

*/
-------------
//编辑距离 
#include<iostream>
#include<cstring> 
using namespace std;
int dp[105][105];
string a,b;
int main(){
	cin>>a>>b;
	int lena=a.size();
	int lenb=b.size();
	for(int i=1;i<=lena;i++){
		dp[i][0]=i;
	}
	for(int i=1;i<=lenb;i++){
		dp[0][1]=i;
	}
	for(int i=1;i<=lena;i++){
		for(int j=1;j<=lenb;j++){
			if(a[i-1]==b[i-1]){
				dp[i][j]=dp[i-1][j-1];
			}else{
				dp[i][j]=min(min(dp[i][j-1],dp[i-1][j]),dp[i-1][j-1])+1;
			}
		}
	}
	cout<<dp[lena][lenb]<<endl;
	return 0;
} 
/*
cin:
	abcd
	acef
cout:
	3
*/



日期/字符串/进制转换:

-------------------------------------------
1.模拟法:记住某天是星期几(例如公元11日是星期一),然后一天天模拟计算
        
    	#include<iostream>
        using namespace std;

        int whatday(int y,int m,int d){
            int ans=0;
            //计算过去当前年之后是星期几,从1月1日星期一开始计算 
            for(int i=1;i<y;i++){
                if((i%100!=0 && i%4==0) || (i%400==0) ){
                    //闰年 
                    ans+=366%7;//
                    ans %=7; 
                } else{
                    ans += 365%7;
                    ans %= 7;
                }
            }
            //计算过去当前月之后,是星期几 
            for(int i=1;i<m;i++){
                if(i==1 || i==3 || i==5 || i==7 || i==8 || i==10 || i==12){
                    ans+=31%7;
                    ans%=7;
                } else if(i==4 || i==6 || i==9 || i==11){
                    ans+=30%7;
                    ans%=7;
                }else if((y%100!=0 && y%4==0)|| y%400==0){
                    ans+=29%7;
                    ans%=7;
                }else{
                    ans+=28%7;
                    ans%=7;
                }
            }
            //计算过去几天后 
            ans+=(d-1)%7;
            ans %= 7;

            return ans; 
        }
        string weekday[7]={"Monday","Tuesday","Wednesday","Thursday","Friday","Saturday","Sunday"};
        int main() {
             int y,m,d;
             cin>>y>>m>>d;
             cout<<weekday[whatday(y,m,d)]<<endl; 
        }


2.菜吉姆拉尔森计算公式:设星期为w,年份为y,月份为m,日期为d
    w=(d+2*m+3*(m+1)/5+y+y/4-y/100+y/400)%7
    在把计算的w+1就是真正的星期几
    注:每年的1,2月要当成上一年的13,14月来计算
  
      int main() {
        //w=(d+2xm+3x(m+1)/5+y+y/4-y/100+y/400)%7
        int w,d,m,y;
        cout<<"年";	cin>>y;
        cout<<"月";	cin>>m;
        cout<<"日";	cin>>d; 

        if(m==1){
            m=13;
            y=y-1;
        }
        if(m==2){
            m=14;
            y=y-1;
        }
        w=(d+2*m+3*(m+1)/5+y+y/4-y/100+y/400)%7;
        cout<<"星期"<<w+1<<endl;

        return 0;
    }

-----------------------
输入:一个开始日期	几天后
输出:一个日期
#include <bits/stdc++.h>
using namespace std;
int main(){
	int year,month,day,n;
	int mon[13]={0,31,28,31,30,31,30,31,31,30,31,30,31};
	while(scanf("%d-%d-%d%d",&year,&month,&day,&n)!=EOF){
		if((year%4==0&&year%100!=0)||year%400==0){//判断闰年 
				mon[2]=29;
		}
		else
			mon[2]=28;
		for(int i=1;i<=n;i++){	
			day+=1;
			if(day>mon[month]){
				day=day-mon[month];
				month++;
				if(month>12){
					year++;
					month=1;
					if((year%4==0&&year%100!=0)||year%400==0){//判断闰年 
						mon[2]=29;
					}
					else
						mon[2]=28;	
				}
			}
		}
		printf("%02d-%02d-%02d\n",year,month,day);
	}
	return 0;
}

---------------------------
进制转换:
#include<bits/stdc++.h>
using namespace std;
string s;
//16-10-8
int f(string s){
	int sum=0;
	for(int i=0;i<s.length();i++){
		if(s[i]>='A'&&s[i]<='F')
			sum=sum*16+s[i]-'A'+10;
		else
			sum=sum*16+s[i]-'0';
	} 
	int t[100],num=0;
	while(sum>0){
		t[num++]=sum%8;
		sum/=8;
	}
	for(int i=sum-1;i>=0;i--){
		cout<<t[i];
	}
	
}
int main(){
	cin>>s;
	f(s); 
	return 0;
}
--------------------------
#include<bits/stdc++.h>
using namespace std;
int main(){
    string str ="123456789abcdefghiaklmn";

    for(int i=0;i<10;i++)   //把str看成一个字符串数组
        cout<<str[i]<<" ";
    cout << endl;

//find函数
    cout<<"123的位置:   "<<str.find("123")<<endl;
//输出:123的位置:   0
    cout<<"34在str[2]到str[n-1]中的位置:   "<<str.find("34",2)<<endl;
//输出:34在str[2]到str[n-1]中的位置:   2
    cout<<"ab在str[0]到str[12]中的位置:    "<<str.rfind("ab",12)<<endl;
//输出:ab在str[0]到str[12]中的位置:    9

//substr()函数
    cout<<"str[3]及以后的子串:"<<str.substr(3)<<endl;
//输出:str[3]及以后的子串:456789abcdefghijklmn
//若小于限制长度则报错
    cout<<"从str[2]开始的4个字符:"<<str.substr(2,4)<<endl;
//输出:从str[2]开始的4个字符:3456

//find()函数
    str.replace(str.find("a"), 5, "@#");
    cout<<str<<endl;
//输出:123456789@#fghiaklmn

//insert()函数
    str.insert(2, "***");
    cout<<"从2号位置插入: "<<str<<endl;
//输出:12***3456789@#fghiaklmn

//添加字符串:append()函数
    str.append("$$$");
    cout<<"在字符串str后面添加字符串:"<<str<<endl;
//输出: 12***3456789@#fghiaklmn$$$

//字符串长度
    cout<<str.size()<<endl;
    cout<<str.length()<<endl;

//交换字符串:swap()函数
    string str1="aaa",str2="bbb";
    swap(str1, str2);
    cout<<str1<<"  "<<str2<<endl;

//字符串比较函数:compare(),相等输出0,不等输出1
    cout<<str1.compare(str2)<<endl;
    if(str1==str2) cout <<"==";   //直接比较也行
    if(str1!=str2) cout <<"!=";

    return 0;
}

c++(stl):

vector, 变长数组,倍增的思想
    size()  返回元素个数
    empty()  返回是否为空
    clear()  清空
    front()/back()
    push_back()/pop_back()
    begin()/end()
    []
    支持比较运算,按字典序

pair<int, int>
    first, 第一个元素
    second, 第二个元素
    支持比较运算,以first为第一关键字,以second为第二关键字(字典序)

string,字符串
    size()/length()  返回字符串长度
    empty()
    clear()
    substr(起始下标,(子串长度))  返回子串
    c_str()  返回字符串所在字符数组的起始地址

queue, 队列
    size()
    empty()
    push()  向队尾插入一个元素
    front()  返回队头元素
    back()  返回队尾元素
    pop()  弹出队头元素

priority_queue, 优先队列,默认是大根堆
    size()
    empty()
    push()  插入一个元素
    top()  返回堆顶元素
    pop()  弹出堆顶元素
    定义成小根堆的方式:priority_queue<int, vector<int>, greater<int>> q;

stack,size()
    empty()
    push()  向栈顶插入一个元素
    top()  返回栈顶元素
    pop()  弹出栈顶元素

deque, 双端队列
    size()
    empty()
    clear()
    front()/back()
    push_back()/pop_back()
    push_front()/pop_front()
    begin()/end()
    []

set, map, multiset, multimap, 基于平衡二叉树(红黑树),动态维护有序序列
    size()
    empty()
    clear()
    begin()/end()
    ++, -- 返回前驱和后继,时间复杂度 O(logn)

    set/multiset
        insert()  插入一个数
        find()  查找一个数
        count()  返回某一个数的个数
        erase()
            (1) 输入是一个数x,删除所有x   O(k + logn)
            (2) 输入一个迭代器,删除这个迭代器
        lower_bound()/upper_bound()
            lower_bound(x)  返回大于等于x的最小的数的迭代器
            upper_bound(x)  返回大于x的最小的数的迭代器
    map/multimap
        insert()  插入的数是一个pair
        erase()  输入的参数是pair或者迭代器
        find()
        []  注意multimap不支持此操作。 时间复杂度是 O(logn)
        lower_bound()/upper_bound()

unordered_set, unordered_map, unordered_multiset, unordered_multimap, 哈希表
    和上面类似,增删改查的时间复杂度是 O(1)
    不支持 lower_bound()/upper_bound(), 迭代器的++--

bitset, 圧位
    bitset<10000> s;
    ~, &, |, ^
    >>, <<
    ==, !=
    []

    count()  返回有多少个1

    any()  判断是否至少有一个1
    none()  判断是否全为0

    set()  把所有位置成1
    set(k, v)  将第k位变成v
    reset()  把所有位变成0
    flip()  等价于~
    flip(k) 把第k位取反

数学:

1.
bool is_prime(int x)
{
    if (x < 2) return false;
    for (int i = 2; i <= x / i; i ++ )
        if (x % i == 0)
            return false;
    return true;
}
2.
void divide(int x)
{
    for (int i = 2; i <= x / i; i ++ )
        if (x % i == 0)
        {
            int s = 0;
            while (x % i == 0) x /= i, s ++ ;
            cout << i << ' ' << s << endl;
        }
    if (x > 1) cout << x << ' ' << 1 << endl;
    cout << endl;
}
3.
int primes[N], cnt;     // primes[]存储所有素数
bool st[N];         // st[x]存储x是否被筛掉

void get_primes(int n)
{
    for (int i = 2; i <= n; i ++ )
    {
        if (st[i]) continue;
        primes[cnt ++ ] = i;
        for (int j = i + i; j <= n; j += i)
            st[j] = true;
    }
}
4.
int primes[N], cnt;     // primes[]存储所有素数
bool st[N];         // st[x]存储x是否被筛掉

void get_primes(int n)
{
    for (int i = 2; i <= n; i ++ )
    {
        if (!st[i]) primes[cnt ++ ] = i;
        for (int j = 0; primes[j] <= n / i; j ++ )
        {
            st[primes[j] * i] = true;
            if (i % primes[j] == 0) break;
        }
    }
}
5.
vector<int> get_divisors(int x)
{
    vector<int> res;
    for (int i = 1; i <= x / i; i ++ )
        if (x % i == 0)
        {
            res.push_back(i);
            if (i != x / i) res.push_back(x / i);
        }
    sort(res.begin(), res.end());
    return res;
}
6.
int gcd(int a, int b)
{
    return b ? gcd(b, a % b) : a;
}
__gcd(a,b)
a*b/__gcd(a,b)
7.
//m^k mod p
int qmi(int m, int k, int p)
{
    int res = 1 % p, t = m;
    while (k)
    {
        if (k&1) res = res * t % p;
        t = t * t % p;
        k >>= 1;
    }
    return res;
}
8.
// c[a][b] 表示从a个苹果中选b个的方案数
for (int i = 0; i < N; i ++ )
    for (int j = 0; j <= i; j ++ )
        if (!j) c[i][j] = 1;
        else c[i][j] = (c[i - 1][j] + c[i - 1][j - 1]) % mod;


9.
//组合数顶配 ,笑死 
#include <iostream>
#include <algorithm>

using namespace std;

typedef long long LL;


int qmi(int a, int k, int p)
{
    int res = 1;
    while (k)
    {
        if (k & 1) res = (LL)res * a % p;
        a = (LL)a * a % p;
        k >>= 1;
    }
    return res;
}


int C(int a, int b, int p)
{
    if (b > a) return 0;

    int res = 1;
    for (int i = 1, j = a; i <= b; i ++, j -- )
    {
        res = (LL)res * j % p;
        res = (LL)res * qmi(i, p - 2, p) % p;
    }
    return res;
}


int lucas(LL a, LL b, int p)
{
    if (a < p && b < p) return C(a, b, p);
    return (LL)C(a % p, b % p, p) * lucas(a / p, b / p, p) % p;
}


int main()
{
        LL a, b;
        int p;
        cin >> a >> b >> p;
        cout << lucas(a, b, p) << endl;
    
    return 0;
}
10.
n!0的个数 
#include <cstdio>

int main() {
    int n;
    scanf("%d", &n);
    int ans = 0;
    while (n) {
        ans += n / 5;
        n /= 5;
    }
    printf("%d", ans);
    return 0;
}



高精度:

#include <iostream>
#include <vector>

using namespace std;

vector<int> add(vector<int> &A, vector<int> &B)
{
    if (A.size() < B.size()) return add(B, A);

    vector<int> C;
    int t = 0;
    for (int i = 0; i < A.size(); i ++ )
    {
        t += A[i];
        if (i < B.size()) t += B[i];
        C.push_back(t % 10);
        t /= 10;
    }

    if (t) C.push_back(t);
    return C;
}

int main()
{
    string a, b;
    vector<int> A, B;
    cin >> a >> b;
    for (int i = a.size() - 1; i >= 0; i -- ) A.push_back(a[i] - '0');
    for (int i = b.size() - 1; i >= 0; i -- ) B.push_back(b[i] - '0');

    vector<int> C = add(A, B);

    for (int i = C.size() - 1; i >= 0; i -- ) cout << C[i];
    // cout << endl;

    return 0;
}


--------------------
#include <iostream>
#include <vector>

using namespace std;

bool cmp(vector<int> &A, vector<int> &B)
{
    if (A.size() != B.size()) return A.size() > B.size();

    for (int i = A.size() - 1; i >= 0; i -- )
        if (A[i] != B[i])
            return A[i] > B[i];

    return true;
}

vector<int> sub(vector<int> &A, vector<int> &B)
{
    vector<int> C;
    for (int i = 0, t = 0; i < A.size(); i ++ )
    {
        t = A[i] - t;
        if (i < B.size()) t -= B[i];
        C.push_back((t + 10) % 10);
        if (t < 0) t = 1;
        else t = 0;
    }

    while (C.size() > 1 && C.back() == 0) C.pop_back();
    return C;
}

int main()
{
    string a, b;
    vector<int> A, B;
    cin >> a >> b;
    for (int i = a.size() - 1; i >= 0; i -- ) A.push_back(a[i] - '0');
    for (int i = b.size() - 1; i >= 0; i -- ) B.push_back(b[i] - '0');

    vector<int> C;

    if (cmp(A, B)) C = sub(A, B);
    else C = sub(B, A), cout << '-';

    for (int i = C.size() - 1; i >= 0; i -- ) cout << C[i];
    cout << endl;

    return 0;
}
------------------------------------
#include <iostream>
#include <vector>

using namespace std;


vector<int> mul(vector<int> &A, int b)
{
    vector<int> C;

    int t = 0;
    for (int i = 0; i < A.size() || t; i ++ )
    {
        if (i < A.size()) t += A[i] * b;
        C.push_back(t % 10);
        t /= 10;
    }

    while (C.size() > 1 && C.back() == 0) C.pop_back();

    return C;
}


int main()
{
    string a;
    int b;

    cin >> a >> b;

    vector<int> A;
    for (int i = a.size() - 1; i >= 0; i -- ) A.push_back(a[i] - '0');

    auto C = mul(A, b);

    for (int i = C.size() - 1; i >= 0; i -- ) printf("%d", C[i]);

    return 0;
}
----------------
#include <iostream>
#include <vector>
#include <algorithm>

using namespace std;

vector<int> div(vector<int> &A, int b, int &r)
{
    vector<int> C;
    r = 0;
    for (int i = A.size() - 1; i >= 0; i -- )
    {
        r = r * 10 + A[i];
        C.push_back(r / b);
        r %= b;
    }
    reverse(C.begin(), C.end());
    while (C.size() > 1 && C.back() == 0) C.pop_back();
    return C;
}

int main()
{
    string a;
    vector<int> A;

    int B;
    cin >> a >> B;
    for (int i = a.size() - 1; i >= 0; i -- ) A.push_back(a[i] - '0');

    int r;
    auto C = div(A, B, r);

    for (int i = C.size() - 1; i >= 0; i -- ) cout << C[i];

    cout << endl << r << endl;

    return 0;
}
-----------------

并查集/最短路/前缀和(一维和二维)


并查集
#include<bits/stdc++.h>
using namespace std;
const int N=110;
bool root[110];
int father[110];
int findfather(int x){
	int a=x;
	while(x!=father[x]){
		x=father[x];
	}
	while(a!=father[a]){
		int z=a;
		a=father[a];
		father[z]=x;
	}
	return x;
}

void Union(int a,int b){
	int fa=findfather(a);
	int fb=findfather(b);
	if(fa!=fb){
		father[fa]=fb;
	}
}
void init(int n){
	for(int i=1;i<=n;i++){
		father[i]=i;
	}	
}
int main(){
	int n,m;
	int a,b;
	cin>>n>>m;
	init(n);
	for(int i=0;i<m;i++){
		cin>>a>>b;
		Union(a,b);
	}
	for(int i=1;i<=n;i++){
		root[findfather(i)]=true;
	}
	int ans=0;
	for(int i=1;i<=n;i++){
		ans+=root[i];
	}
	cout<<ans<<endl;
	return 0;
}
(1)朴素并查集:

    int p[N]; //存储每个点的祖宗节点

    // 返回x的祖宗节点
    int find(int x)
    {
        if (p[x] != x) p[x] = find(p[x]);
        return p[x];
    }

    // 初始化,假定节点编号是1~n
    for (int i = 1; i <= n; i ++ ) p[i] = i;

    // 合并a和b所在的两个集合:
    p[find(a)] = find(b);


(2)维护size的并查集:

    int p[N], size[N];
    //p[]存储每个点的祖宗节点, size[]只有祖宗节点的有意义,表示祖宗节点所在集合中的点的数量

    // 返回x的祖宗节点
    int find(int x)
    {
        if (p[x] != x) p[x] = find(p[x]);
        return p[x];
    }

    // 初始化,假定节点编号是1~n
    for (int i = 1; i <= n; i ++ )
    {
        p[i] = i;
        size[i] = 1;
    }

    // 合并a和b所在的两个集合:
    size[find(b)] += size[find(a)];
    p[find(a)] = find(b);


(3)维护到祖宗节点距离的并查集:

    int p[N], d[N];
    //p[]存储每个点的祖宗节点, d[x]存储x到p[x]的距离

    // 返回x的祖宗节点
    int find(int x)
    {
        if (p[x] != x)
        {
            int u = find(p[x]);
            d[x] += d[p[x]];
            p[x] = u;
        }
        return p[x];
    }

    // 初始化,假定节点编号是1~n
    for (int i = 1; i <= n; i ++ )
    {
        p[i] = i;
        d[i] = 0;
    }

    // 合并a和b所在的两个集合:
    p[find(a)] = find(b);
    d[find(a)] = distance; // 根据具体问题,初始化find(a)的偏移量

-----------
floyd算法
初始化:
    for (int i = 1; i <= n; i ++ )
        for (int j = 1; j <= n; j ++ )
            if (i == j) d[i][j] = 0;
            else d[i][j] = INF;

// 算法结束后,d[a][b]表示a到b的最短距离
void floyd()
{
    for (int k = 1; k <= n; k ++ )
        for (int i = 1; i <= n; i ++ )
            for (int j = 1; j <= n; j ++ )
                d[i][j] = min(d[i][j], d[i][k] + d[k][j]);
}
-----------------
int g[N][N];  // 存储每条边
int dist[N];  // 存储1号点到每个点的最短距离
bool st[N];   // 存储每个点的最短路是否已经确定

// 求1号点到n号点的最短路,如果不存在则返回-1
int dijkstra()
{
    memset(dist, 0x3f, sizeof dist);
    dist[1] = 0;

    for (int i = 0; i < n - 1; i ++ )
    {
        int t = -1;     // 在还未确定最短路的点中,寻找距离最小的点
        for (int j = 1; j <= n; j ++ )
            if (!st[j] && (t == -1 || dist[t] > dist[j]))
                t = j;

        // 用t更新其他点的距离
        for (int j = 1; j <= n; j ++ )
            dist[j] = min(dist[j], dist[t] + g[t][j]);

        st[t] = true;
    }

    if (dist[n] == 0x3f3f3f3f) return -1;
    return dist[n];
}
----------------------------
bool check(int x) {/* ... */} // 检查x是否满足某种性质

// 区间[l, r]被划分成[l, mid]和[mid + 1, r]时使用:
int bsearch_1(int l, int r)
{
    while (l < r)
    {
        int mid = l + r >> 1;
        if (check(mid)) r = mid;    // check()判断mid是否满足性质
        else l = mid + 1;
    }
    return l;
}
// 区间[l, r]被划分成[l, mid - 1]和[mid, r]时使用:
int bsearch_2(int l, int r)
{
    while (l < r)
    {
        int mid = l + r + 1 >> 1;
        if (check(mid)) l = mid;
        else r = mid - 1;
    }
    return l;
}
----------------
#include<iostream>
#include<cstdio>
using namespace std;
const int N=1e5+10;
int a[N],sum[N];
int main()
{
    int n,m,x;
    cin>>n>>m;
    for(int i=1;i<=n;i++)
    {
        cin>>x;
        sum[i]=x+sum[i-1];
    }
    while(m--)
    {
        int l,r;
        cin>>l>>r;
        cout<<sum[r]-sum[l-1]<<endl;
    }
    return 0;
}


---------------
#include <iostream>

using namespace std;

const int N = 1010;

int n, m, q;
int s[N][N];

int main()
{
    scanf("%d%d%d", &n, &m, &q);

    for (int i = 1; i <= n; i ++ )
        for (int j = 1; j <= m; j ++ )
            scanf("%d", &s[i][j]);

    for (int i = 1; i <= n; i ++ )
        for (int j = 1; j <= m; j ++ )
            s[i][j] += s[i - 1][j] + s[i][j - 1] - s[i - 1][j - 1];

    while (q -- )
    {
        int x1, y1, x2, y2;
        scanf("%d%d%d%d", &x1, &y1, &x2, &y2);
        printf("%d\n", s[x2][y2] - s[x1 - 1][y2] - s[x2][y1 - 1] + s[x1 - 1][y1 - 1]);
    }

    return 0;
}


全排列/dfs/bfs典型入门题(能力有限)

#include <bits/stdc++.h>
using namespace std;
int main(){
    string s="bca"; 
    sort(s.begin(),s.end());  //字符串内部排序,得到最小的排列“abc”
    do{ 
       cout<<s<<endl;
    }while(next_permutation(s.begin(),s.end()));
    return 0;
}   
--------------------------
#include<iostream>
using namespace std;
int n;
bool vis[16];
void dfs(int x){
    if(x>n){
        for(int i=1;i<=n;i++){
            if(vis[i]){
                cout<<i<<" ";
            }
        }
        cout<<"\n";
        return ;
    }
    vis[x]=1;
    dfs(x+1);
    
    vis[x]=0;
    dfs(x+1);
    
    
}
int main(){
  
    cin>>n;
    dfs(1);
    
    return 0;
}
---------------
#include<iostream>
using namespace std;
int n;
bool vis[10];
int path[10];
void dfs(int x){
    if(x>n){
        for(int i=1;i<=n;i++){
            cout<<path[i]<<" ";
        }
        cout<<"\n";
        return ;
    }
    for(int i=1;i<=n;i++){
        if(!vis[i]){
            vis[i]=1;
           
            path[i]=x;//
           
            dfs(x+1);
            vis[i]=0;
            
            path[i]=0;//注意
        }
    }
}
int main(){
    cin>>n;
    dfs(1);
    return 0;
}
---------------------
dfs 
//迷宫问题(改版)
#include<iostream>
#include<string>
using namespace std;
int n,m;
string maze[110];
bool vis[110][110];

int  dir[4][2]={{-1,0},{0,-1},{1,0},{0,1}};//移动坐标 
//建议按照 逆时针 (或顺时针)方向写,方便做转头操作 

bool in(int x,int y){
	return 0<=x && x<n && 0<=y && y<m;
}

bool dfs(int x,int y){
	//找到重点 
	if(maze[x][y]=='T'){
		return true;
	}
	
	vis[x][y]=1;//走过了 
	maze[x][y]='+';//标记为+
	
	for(int i=0;i<4;i++){
		int tx=x+dir[i][0];
		int ty=y+dir[i][1];
		if(in(tx,ty)&&maze[tx][ty]!='*'&&!vis[tx][ty]){
			if(dfs(tx,ty)){
				return true;	
			}
		}
	} 
	//走不通,取消标记
	vis[x][y]=0;
	maze[x][y]='.';
	return false; 
}


int main(){
	
	//输入迷宫地图 
	cin>>n>>m;
	for(int i=0;i<n;i++){
		cin>>maze[i];
	} 
	//寻找起始点 
	int x,y;
	for(int i=0;i<n;i++){
		for(int j=0;j<m;j++){
			if(maze[i][j]=='S'){
				x=i,y=j;
			}
		}
	}
	//打印地图 
	if(dfs(x,y)){
		for(int i=0;i<n;i++){
			cout<<maze[i]<<endl;
		}
	} else {
		cout<<"No!"<<endl;
	}
	
	
	return 0;
} 

//
-----------------
bfs 
#include<iostream>
#include<queue> 
using namespace std;
int n,m;
char maze[105][105];
bool vis[105][105];
int dir[4][2]={{-1,0},{0,-1},{1,0},{0,1}};//方向
bool in(int x,int y){//范围
	return x>=0 && x<n && y>=0 && y<m;
}
//节点
struct node{
	int x,y,d;
	node(int xx,int yy,int dd){
		x=xx;
		y=yy;
		d=dd;
	}
};

int bfs(int sx,int sy){
	queue<node> q;
	q.push(node(sx,sy,0));
	vis[sx][sy]=true;
	while(!q.empty()){
		node now=q.front();
		q.pop();
		for(int i=0;i<4;i++){
			int tx=now.x+dir[i][0];
			int ty=now.y+dir[i][1];
			if(in(tx,ty) && maze[tx][ty]!='*' && !vis[tx][ty]){
				if(maze[tx][ty]=='T'){
					return now.d +1; 
				}else{
					vis[tx][ty]=true;
					q.push(node(tx,ty,now.d+1));
				}
			}
		}
	} 
	return -1;
}

int main(){
	cin>>n>>m;
	for(int i=0;i<n;i++){
		for(int j=0;j<m;j++){
			cin>>maze[i][j];
		}
	}
	
	int x,y;
	for(int i=0;i<n;i++){
		for(int j=0;j<m;j++){
			if(maze[i][j]=='S'){
				x=i;
				y=j;
			}
		}
	}
	
	cout<<bfs(x,y)<<endl; 
	
	return 0;
}

/*
样例输入:
5 6
....S*
.**...
.*..*.
*..**.
.T....

样例输出: 
7

*/
--------------
/*在长度为【0,n】的一维坐标中,输入A,B的地址,问能否从A到B。
移动方式:向前一步(坐标+1),向后一步(坐标-1),跳(坐标*2)*/
#include<iostream>
#include<queue>
#include<utility>
using namespace std;
bool vis[100];
int main() {
	int n,A,B,now,step;
	cin>>n>>A>>B;

	queue< pair<int,int> >q;
	q.push(make_pair(A,0));
	vis[A]=true;
	while(!q.empty()) {
		
		now=q.front().first;
		step=q.front().second;
		
		q.pop();
		if(now==B){
			cout<<step<<endl;
			break;
		}
		if(now+1<=n && !vis[now+1]) {
			q.push(make_pair(now+1,step+1));
			vis[now+1]=true;
		}
		if(now-1>=0 && !vis[now-1]) {
			q.push(make_pair(now-1,step+1));
			vis[now-1]=true;
		}
		if(now*2<=n && !vis[now*2]) {
			q.push(make_pair(now*2,step+1));
			vis[now*2]=true;
		}
	}


	return 0;
}
/*
样例输入:
10 2 7
样例输出
3
*/
------------------------
dfs
#include<iostream>
using namespace std;
int n,k,sum,ans;
int a[100];

void dfs(int i,int cnt,int s){
	if(i==n){
		if(cnt==k && s==sum){
			ans++;
		}
		return ;
	}
	dfs(i+1,cnt,s);//不选 a[i] 
	dfs(i+1,cnt+1,s+a[i]);//选 a[i] 
}

int main(){
	cin>>n>>k>>sum;
	for(int i=0;i<n;i++){
		cin>>a[i];
	}
	ans=0;
	dfs(0,0,0);
	cout<<ans<<endl;
	return 0;
}
/*
输入:
5 3 9
1 2 3 4 5
输出: 
2 
*/
 

问题:

INF=-0x3f3f3f3f//
INF=0x3f3f3f3f//
string space=string(n-i,' ');//
for(vector<int>::iterator it=ve.begin();it!=ve.end();it++){
		cout<<*it<<" ";
	} 
struct Student {
	int score;
	string name;
	Student(){}//可是省略 
	Student(string name,int s) {
		name=n;
		score=s;
	}

}
struct Student{
	int score;
	string name;
	Student() {} //不可以省
	Student(string n,int s):name(n),score(s){} 
};
---------------

//最大矩阵暴力 
int n,m,ans;
	cin>>n>>m;
	ans=-1005;//足够小
	for(int i=0;i<n;i++){
		for(int j=0;j<m;j++){
			cin>>A[i][j];
		}
	} 
	for(int i=0;i<n;i++){
		for(int j=i;j<n;j++){
			for(int k=0;k<m;k++){
				for(int l=k;l<m;l++){
					int temp=0;//代表空矩阵 
					for(int p=i;p<=j;p++){
						for(int q=k;q<=l;q++){
							temp=temp+A[p][q];
						}
					}
					if(temp>ans){
						ans=temp;
					}
					
				}
			}
		}
	}
	
	cout<<ans<<endl;
----------------	
//最大子矩阵和 
#include<iostream>
#include<cstdio>
using namespace std;
long long num[401][401];
long long presum[401][401];
int main(){
	int N,M;
	long long sum,ans;
	cin>>N>>M;
	ans=-100000;
	for(int i=1;i<=N;i++){
		for(int j=1;j<=M;j++){
			cin>>num[i][j];
			ans=max(ans,num[i][j]);
		}
	}
	if(ans<=0){
		cout<<ans<<endl;
	}else{
		for(int i=1;i<=N;i++){
			for(int j=1;j<=M;j++){
				presum[i][j]=presum[i-1][j]+num[i][j];
			}
		}
		for(int i=1;i<=N;i++){
			for(int j=i;j<=N;j++){
				sum=0;
				for(int k=1;k<=M;k++){
					if(sum+presum[j][k]-presum[i-1][k]<0){
						sum=0;
					}else{
						sum+=presum[j][k]-presum[i-1][k];
					}
					ans=max(ans,sum);
				}
			}
		}
	}
	
	cout<<ans<<endl;
	return 0;
}
/*
--cin:
3 3
1 2 3
4 -5 6
7 8 9
--cout:
35
*/

-----------------	
	bool judge(int x){
	int cnt=0;//记录位数 
	while(x){
		digit[cnt++]=x%10;
		x/=10;
	}
	for(int i=0;i<cnt/2;i++){
		if(digit[i]!=digit[cnt-1-i]){
			return false;
		}
	}
	return true;
} 
---------
#include<iostream>
using namespace std;
int dir[8][2]= {{1,2},{1,-2},{2,1},{2,-1},{-1,2},{-1,-2},{-2,1},{-2,-1}};
bool  d[30][30];
long long dp[30][30];
int main() {
	int n,m,cx,cy;// n,m棋盘大小  cx,xy马的位置
	cin>>n>>m>>cx>>cy;
	d[cx][cy]=true;
	for(int i=0; i<8; i++) {
		int tx=cx+dir[i][0];
		int ty=cy+dir[i][1];
		if(tx>=0 && tx<=n && ty>=0 && ty<=n) {
			d[tx][ty]=true;//记录为马控制点
		}
	}

	dp[0][0]=1;//dp[n][m]即为从(0,0)到(n,m)的路径数目
	for(int i=0; i<=n; i++) {
		for(int j=0; j<=m; j++) {
			if(d[i][j]==false) {
				if(i) {
					dp[i][j]+=dp[i-1][j];
				}
				if(j) {
					dp[i][j]+=dp[i][j-1];
				}
			}
		}
	}

	cout<<dp[n][m]<<endl;
	return 0;
}
/*
样例输入:
5 5 2 4
样例输出:
14 
*/
-------------
//约瑟夫环 
//猴子选大王 --
#include<iostream>
#include<queue>
using namespace std;

int main() {
	int n,m=3;
	cin>>n;
	queue<int> q;
	for(int i=1;i<=n;i++){
		q.push(i);
	}
	int cur=1;
	while(q.size()>1){
		int x=q.front();
		q.pop();
		if(cur!=m){
			q.push(x);
			cur++;
		} else{
			cur=1;
		}
	}
	cout<<q.front()<<endl;
}
------------
//二进制优化版本
#include<iostream>
using namespace std;

const int N = 12010, M = 2010;

int n, m;
int v[N], w[N]; //逐一枚举最大是N*logS
int f[M]; // 体积<M

int main()
{
    cin >> n >> m;
    int cnt = 0; //分组的组别
    for(int i = 1;i <= n;i ++)
    {
        int a,b,s;
        cin >> a >> b >> s;//v体积 w价值 s数量 
        int k = 1; // 组别里面的个数
        while(k<=s)
        {
            cnt ++ ; //组别先增加
            v[cnt] = a * k ; //整体体积
            w[cnt] = b * k; // 整体价值
            s -= k; // s要减小
            k *= 2; // 组别里的个数增加
        }
        //剩余的一组
        if(s>0)
        {
            cnt ++ ;
            v[cnt] = a*s; 
            w[cnt] = b*s;
        }
    }

    n = cnt ; //枚举次数正式由个数变成组别数

    //01背包一维优化
    for(int i = 1;i <= n ;i ++)
        for(int j = m ;j >= v[i];j --)
            f[j] = max(f[j],f[j-v[i]] + w[i]);

    cout << f[m] << endl;
    return 0;
}


接下来最后总结一下dp(背典型)`

三包tmd 
---------------
01背包 (二维) 
#include<bits/stdc++.h>
using namespace std;
const int MAXN = 1005;
int v[MAXN];    // 体积
int w[MAXN];    // 价值 
int dp[MAXN][MAXN];  // f[i][j], j体积下前i个物品的最大价值 

int main() 
{
    int n, m;   
    cin >> n >> m;
    for(int i = 1; i <= n; i++) 
        cin >> v[i] >> w[i];

    for(int i = 1; i <= n; i++) 
        for(int j = 1; j <= m; j++)
        {
            //  当前背包容量装不进第i个物品,则价值等于前i-1个物品
            if(j < v[i]) 
                dp[i][j] = dp[i - 1][j];
            // 能装,需进行决策是否选择第i个物品
            else    
                dp[i][j] = max(dp[i - 1][j], dp[i - 1][j - v[i]] + w[i]);
        }           

    cout << dp[n][m] << endl;

    return 0;
}

01背包(一维)
#include<bits/stdc++.h>
using namespace std;
const int N = 1010;
int f[N];
int v[N], w[N];
int n, m;
int main()
{
   
    cin >> n >> m;
    for (int i = 1; i <= n; i ++ ) cin >> v[i] >> w[i];

    for (int i = 1; i <= n; i++) {
        for (int j = m; j >= v[i]; j--) {
            f[j] = max(f[j], f[j - v[i]] + w[i]);
        }
    }

    cout << f[m] << endl;
}

 
--------------------
 多重背包(二维度) 
#include<iostream>
#include<algorithm>
using namespace std;
const int N=1e2+10;
int  f[N][N],w[N],v[N],s[N];
int main()
{
    int n,V;
    cin>>n>>V;
    for(int i=1;i<=n;i++) cin>>v[i]>>w[i]>>s[i];
    for(int i=1;i<=n;i++)
    {
        for(int j=0;j<=V;j++)
        {
            for(int k=0;k<=s[i];k++)
            {
                if(k*v[i]<=j) f[i][j]=max(f[i][j],f[i-1][j-k*v[i]]+k*w[i]);
            }
        }
    }
    cout<<f[n][V];
    return 0;
}
多重背包(一维)
#include <bits/stdc++.h>
using namespace std;

int N, V, u,w, s, f[10500];
int main() {
    cin >> N >> V;
    for (int i = 0; i < N; i++) {
        cin >> u >> w >> s;
        for (int j = V; j >= u; j--)
            for (int k = 1; k <= s; k++) {
                if (j >= k * u)
                    f[j] = max(f[j], f[j - k * u] + k * w);
                else
                    break;
            }
    }
    cout << f[V] << endl;
    return 0;
}

 
----------------------
完全背包(二维) 
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
int f[1010][1010];
int v[1010],w[1010];
int n,m;
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)
    scanf("%d%d",&v[i],&w[i]);
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=m;j++)
        {
            f[i][j]=f[i-1][j];
            if(j>=v[i])
            {
                f[i][j]=max(f[i][j],f[i][j-v[i]]+w[i]);
            }
        }
    }
    printf("%d\n",f[n][m]);
    return 0;
}


完全背包(一维) 
#include<iostream>
using namespace std;

const int N = 1010;

int n, m;
int dp[N];

int main(){
    cin >> n >> m;
    for(int i = 1; i <= n; i ++ ){
        int v, w;
        cin >> v >> w;
        for(int j = v; j <= m; j ++ ){
                dp[j] = max(dp[j], dp[j - v] + w);
        }
    }
    cout << dp[m] << endl;
}

 
 

典型案例:

--------------
//数字三角形 
#include<bits/stdc++.h>
using namespace std;

const int N=510,INF=0x3f3f3f3f;
int f[N][N];
int a[N][N];

int main(){
    int n;
    cin>>n;

    for(int i=1;i<=n;i++){
        for(int j=1;j<=i;j++){
            cin>>a[i][j];
        }
    }

    for(int i=1;i<=n;i++){             
        for(int j=0;j<=i+1;j++){          //因为有负数,所以应该将两边也设为-INF
            f[i][j]=-INF;
        }
    }

    f[1][1]=a[1][1];
    for(int i=2;i<=n;i++){
        for(int j=1;j<=i;j++){
            f[i][j]=a[i][j]+max(f[i-1][j-1],f[i-1][j]);
        }
    }

    int res=-INF;
    for(int i=1;i<=n;i++) res=max(res,f[n][i]);
    cout<<res<<endl;
}
----------------
//最大连续子序列和
#include <cstdio>
#include <iostream>
using namespace std;

int main()
{
	int n;
	scanf("%d", &n);
	int a[n], dp[n] = { 0 };
	for (int i = 0 ; i < n; i++)
	{
		scanf("%d", &a[i]);
	}
	dp[0] = a[0];
	int ans = -0x3f3f3f3f;
	for (int i = 0; i < n; i++)
	{
		dp[i] = max(a[i], dp[i - 1] + a[i]);
		ans = max(dp[i], ans);
	}
	printf("%d\n", ans);
	return 0;
}
--------------------
//最长上升"子序列"(不连续)
#include<iostream>
#include<cstdio>
using namespace std;

int n,a[105],dp[105];
int ans=0;

int main(){
	cin>>n;
	for(int i=1;i<=n;i++){
		cin>>a[i];
	}	
	
	for(int i=1;i<=n;i++){
		dp[i]=1;
		for(int j=1;j<i;j++){
			if(a[j]<a[i]){
				dp[i]=max(dp[i],dp[j]+1);
			}
		}
		ans=max(ans,dp[i]);
	}
	cout<<ans<<endl;
	return 0;
}
/*
cin:
8
2 1 5 3 6 4 6 3
cout:
4
*/




---------------
//最长公共子序列
#include <iostream>
#include <cstring>
#include <string>
using namespace std;
int dp[110][110];
int main() 
{
    string a, b;
    memset(dp, 0, sizeof(dp));
    cin >> a >> b;
    int lena = a.size();
    int lenb = b.size();
    for (int i = 1; i <= lena; i++)
    {
        for (int j = 1; j <= lenb; j++)
        {
            if (a[i - 1] == b[j - 1])
            {
                dp[i][j] = dp[i - 1][j - 1] + 1;
            }
            else
            {
                dp[i][j] = max(dp[i - 1][j], dp[i][j - 1]);
            }
        }
    }
    cout << dp[lena][lenb] << endl;
    return 0;
}
------------- 
  • 2
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值