复杂问题的小整理

P2670 扫雷游戏
1.设立两个数组,遇到*,就把他八方的+1
2.然后输出,不是*的就输出数字好了

#include<bits/stdc++.h>
using namespace std;
int main()
{   int b[105][105]={0};
char a[105][105];
	int m,n;
	cin>>m>>n;
	for(int i=1;i<=m;i++)
	{
		for(int j=1;j<=n;j++)
		{
			cin>>a[i][j];
			if(a[i][j]=='*')
			{
				
				b[i][j+1]++;
				b[i][j-1]++;
				b[i+1][j]++;
				b[i+1][j-1]++;
				b[i+1][j+1]++;
				b[i-1][j]++;
				b[i-1][j+1]++;
				b[i-1][j-1]++;
				
			}
		}
	}
	for(int i=1;i<=m;i++)
	{
		for(int j=1;j<=n;j++)
		{
			if(a[i][j]=='*')
			cout<<'*';
			else
			cout<<b[i][j];
		}
		cout<<endl;
	}
 } 

dsp想法
1.dx,dy对应八个方向
2.dsp 其实就是把周围的数在没有越界条件下都加上1
3.是地雷就调用它

#include<bits/stdc++.h>
using namespace std;
char a[101][101];//地图
int b[101][101]={0};//答案
int n,m,i,j;
int dx[8]={1,0,-1,0,-1,1,1,-1};
int dy[8]={0,1,0,-1,-1,-1,1,1};
void dsp(int x,int y)
{
int nx,ny,k;
for(k=0;k<8;k++)
{
nx=x+dx[k];
ny=y+dy[k];
if(nx>1&&nx<=n&&ny>=1&&ny<=m)
b[nx][ny]++;
}
}
int main()
{
 cin>>n>>m;//输入
 for (i=1;i<=n;i++)
    for (j=1;j<=m;j++)
        {
        cin>>a[i][j];
        if (a[i][j]=='*')
          dfs(i,j);//如果是地雷就调用函数
        }
 for (i=1;i<=n;i++)
    {
    for (j=1;j<=m;j++)
       if (a[i][j]=='*')//判断是地雷就直接输出
          cout<<a[i][j];
       else
              cout<<b[i][j];//不是地雷输出答案
        cout<<endl;
    }
 return 0;
}

P1601 高精度A+B
孩子永远讨厌高精度
1.输入两个字符串型的数字
2.算出长度
3.摆放到另外一个int型数组中,数组里每个数就是一位,倒序
4.找到和的位数,然后加一加各位
5.前导0记得,倒序输出

#include<bits/stdc++.h>
using namespace std;
int main()
{
	char a[505]={0},b[505]={0};
	int la,lb,x[550]={0},y[505]={0},lh,ans[550]={0};
	cin>>a>>b;
	la=strlen(a);
	lb=strlen(b);
	for(int i=0;i<la;i++)
	{
		x[la-i]=a[i]-'0';
	 
	}
	for(int i=0;i<lb;i++)
	{
		y[lb-i]=b[i]-'0'; 
	}
	lh=max(la,lb)+1;
	for(int i=1;i<=lh;i++)
	{
		ans[i]+=x[i]+y[i];
		ans[i+1]=ans[i]/10;
		ans[i]=ans[i]%10;
		
		
	}
	if(ans[lh]==0&&lh>0)lh--;
	for(int i=lh;i>0;i--)
	{
		cout<<ans[i];
	  }  
	  return 0;
	
	
 } 

P1177 快速排序
我以为我会了
1.最左端,最右端进入
2.记录下这两个,变成两个指针
3.不断比较
4.交换,继续推进
5.继续排左边右边

#include<bits/stdc++.h>
 using namespace std;
 int n,a[1000002];
 void qsort(int left,int right)
 {
 	int i=left,j=right;
 	int mid=a[(left+right)/2];
 	while(i<=j)
 	{
 		if(a[i]<mid)
 		{
 			i++;
 			continue;
		 }
		 if(a[j]>mid)
		 {
		 	j--; 
		 	continue;
		 }
		 if(i<=j)
		 {
		 	swap(a[i],a[j]);
		 i++;
		 j--;
		 }
	 }
	 if(left<j) qsort(left,j);
	 if(i<right) qsort(i,right);
 }
 int main()
 {
 	cin>>n;
 	for(int i=1;i<=n;i++)
 	cin>>a[i];
 	qsort(1,n);
 	for(int i=1;i<=n;i++)
 	cout<<a[i]<<" ";
  } 
 

P1923 求第k小的数
1.stl
nth_element(a+x,a+x+y,a+x+len);
执行之后数组 a下标 x 到 x+y-1 的元素都小于 a[x+y],下标 x+y+1 到 x+len-1的元素 都大于 a[x+y],但不保证数组有序。此时 a[x+y] 就是数组区间 x 到 x+len-1 中第 y 小的数,当然也可以自己定义 cmp函数。

#include<bits/stdc++.h>
using namespace std;
int x[5000005],k;
int main()
{
	int n;
	scanf("%d%d",&n,&k);
	for(int i=0;i<n;i++)
		scanf("%d",&x[i]);
	nth_element(x,x+k,x+n);
	printf("%d",x[k]);
}

2.二分的思想(quicksort)

#include<bits/stdc++.h>
using namespace std;
int x[5000005],k;
void qsort(int l,int r)
{
	int i=l,j=r,mid=x[(l+r)/2];
	do
	{
		while(x[j]>mid)
			j--;
		while(x[i]<mid)
			i++;
		if(i<=j)
		{
			swap(x[i],x[j]);
			i++;
			j--;
		}
	}
	while(i<=j);
	//快排后数组被划分为三块: l<=j<=i<=r
	if(k<=j) qsort(l,j);//在左区间只需要搜左区间
	else if(i<=k) qsort(i,r);//在右区间只需要搜右区间
	else //如果在中间区间直接输出
	{
		printf("%d",x[j+1]);
		exit(0);
	}
}
int main()
{
	int n;
	scanf("%d%d",&n,&k);
	for(int i=0;i<n;i++)
		scanf("%d",&x[i]);
	qsort(0,n-1);
}

P1036选数
主要是想怎么做到全排序:这里是利用循环+不断递归(递归里面再次循环)

#include<bits/stdc++.h> 
using namespace std;
long long int ans=0,a[299]={0},z,g;
bool sushu(int a)
{ 
  if((a==1)||(a==0) )return 0;//1不是质数 
	for(int i=2;i<=sqrt(a);i++)
	 {if(a%i==0)
	  return 0;
	  else continue;
	 }
	 return 1;
	
	 
}

void paixu(int st,int ge,int sum)
{
	if(ge==g)
	{ if(susuh(sum))
	     ans++;
	     return ;
	     }
	  for(int i=st;i<z;i++)
	  {
	     paixu(i+1;ge+1;sum+a[i];
	     }
	     return ;
	     }

int main()
{
	cin>>z>>g;
	for(int i=0;i<z;i++)
	{
		cin>>a[i];
	}
	paixu(0,0,0);
	cout<<ans<<endl;
	return 0;
}

P1706 全排序
1.深搜的边界条件:k==n;
2.1-n循环搜数
3.当前数字没有被使用过,标记他使用过了,然后填入数组(这个很秒,为了让下面的好递归)
4.继续深搜
5.记得要把标记取消掉,方便下一次循环搜数

void dfs(int k)
{
  int i;
  if(k==n)
  {
  print();
  return;}
  for(int i=1;i<=n;i++)
  {if(!pd[i])
  {
     pd[i]=1;
     used[k+1]=i;
     dst(k+1);
     pd[i]=0;}
     }
     }

全排列函数 next_permutation
函数每运行一次就可以把数组排成下一个字典排数

#include<iostream>//P1706
#include<cstdio>
#include<cstring>
#include<string>
#include<iomanip>
#include <algorithm>
#include<cmath>
#include<vector>
#include<set>
using namespace std;
int a[10];
int main()
{
	int n,i,j=1,k;
	cin>>n;
	for(i=1;i<=n;i++)
	 {a[i]=n-i+1;j*=i;}//题目好像没说要从小到大输出
     //但保险起见还是初始赋值为最大序列
     //即a[1~n]=n~1;顺便计算n!
	for(i=1;i<=j;i++)
	 {next_permutation(a+1,a+n+1);
	  for(k=1;k<=n;k++)
	   cout<<"    "<<a[k];//排一次输出一次
       //空格建议复制
	  cout<<endl;
	 }
	 return 0;
}

P1255数楼梯
1.递归人开心得太早,他还有高精度
2.f[k][i] 用来存储走k个阶梯所用的步数走法
f[k][i]=f[k-1]f[i]+f[k-2]f[i];对于每一位
再次循环,该进位的进位
if(f[k][len+1])len++;就是说个位大于10了才有下一位

void jia(int k)
{
for(int i=1;i<=len;i++)
f[k][i]=f[k-1][i]+f[k-2][i];
for(int i=1;i<=len;i++)
if(f[k][i]>10)
{
f[k][i+1]+=f[k][i]/10;
f[k][i]=f[k][i]%10;
if(f[k][len+1])len++;
}


int main()
{
int n;
cin>>n;
f[1][1]=1;
f[2][1]=2;
for(int i=3;i<=n;i++)
jia(i);
for(int i=len,i>=1;i--)
cout<<f[n][i];}

P1449后缀表达式
1.遇到数字就入栈,遇到符号调用前面两个
2.他是有.来表示一个数字结束,所以还要有字符串转换为数字的意识 遇到.的时候将它入栈;
3.遇到符号的时候,栈得倒数第二想重新赋值,然后把站的数量减去一个(数组实现)

#include<bits/stdc++.h>
using namespace std;
int main()
{   long long int zhan[100000]; 
    int num=0,i=0;
    char str;
	while((str=getchar())!='@')
	{
		if(str>='0'&&str<='9')
		{
			num*=10;
			num+=str-'0';
		}
		if(str=='.')
		{	zhan[++i]=num;
		num=0;
		}
	    if(str=='+')
	    {
	    	zhan[i-1]=zhan[i-1]+zhan[i];
	    	zhan[i]=0;
	    	i--;
	    	
		}
		if(str=='-')
	    {
	    	zhan[i-1]=zhan[i-1]-zhan[i];
	    	zhan[i]=0;
	    	i--;
	    	
		}
		if(str=='*')
	    {
	    	zhan[i-1]=zhan[i-1]*zhan[i];
	    	zhan[i]=0;
	    	i--;
	    	
		}
		if(str=='/')
	    {
	    	zhan[i-1]=zhan[i-1]/zhan[i];
	    	zhan[i]=0;
	    	i--;
	    	
		}
	}
	cout<<zhan[1];
	return 0; 
}

直接利用stl的栈
1.出栈两个,两个相加在入栈
2.入栈,到.入栈s

#include <bits/stdc++.h>
using namespace std;
stack<int> n;
char ch;
int s,x,y;
int main()
{
    while(ch!='@')
    {
        ch=getchar();
        switch(ch)
        {
            case '+':x=n.top();n.pop();y=n.top();n.pop();n.push(x+y);break;
            case '-':x=n.top();n.pop();y=n.top();n.pop();n.push(y-x);break;
            case '*':x=n.top();n.pop();y=n.top();n.pop();n.push(x*y);break;
            case '/':x=n.top();n.pop();y=n.top();n.pop();n.push(y/x);break;
            case '.':n.push(s);s=0;break;
            default :s=s*10+ch-'0';break;
        }
    }
    printf("%d\n",n.top());
    return 0;
}

P1996约瑟夫问题
1.用队列去写,每次都加1,到那个数的人出队列,其他的人拍到队伍后面

{
queue<int> q;
int n,m,e=1;
for(int i=1;i<=n;i++)
{
q.push(i);
}
while(!q.empty())
{
if(e==m)
{
cout<<q.front()<<" " :
q.pop();
e=1;
}
else
{
e++;
q.push(q.front())
q.pop();
}

数组模拟链表

#include<iostream>
using namespace std;
int next[1000005];
int main(){
    int n,m;
    cin>>n>>m;//输入n、m
    for(int i=0;i<n;i++)//初始化
    	next[i]=i+1;
	next[n]=1;
	int p=0;
	for(int i=1;i<=n;i++){//开始模拟出圈过程
		for(int j=1;j<m;j++)
			p=next[p];//p位置右移
		cout<<p[next]<<" ";//输出出圈人的位置
		next[p]=next[next[p]];//删掉出圈人
	}
	return 0;//功德圆满
}

n次出圈,所以有个n循环
m此为一个小循环,删掉一个,输出一个
数组代替了链表

#include<iostream>
#include<cstdio>
#include<cstdlib>
using namespace std;
int m,n;
struct Node{
	int data;
	Node*next;
}*head,*p,*tail,*temp; 
int main()
{
	cin>>m>>n;
	head=new Node;
	head->next=NULL;
	tail=head;
	for(int i=1;i<=m;i++)
	{
		p=new Node;
		p->data=i;
		p->next=NULL;
		tail->next=p;
		tail=p;
	 } 
	 p=head->next;
	 tail->next=head->next;
	 for(int i=1;i<=m;i++)
	 {
	 	for(int j=1;j<n-1;j++)
	 	{
	 		p=p->next;
		 }
		 printf("%d",p->next->data);
		 temp=p->next;
		 p->next=temp->next;
		 p=p->next;//更新p 
		 free(temp);
	 }
	 return 0;
 } 

标准的链表:头结点,尾节点,要删除的,临时
建立链表,不断增加节点 new,data和next要写出来
最后做到头尾相连(有点迷惑,要复习循环链表了
最后两次循环
删除出去的,保存,指针的转移,更新p本身,free

P1241括号序列

 #include<stdio.h>
#include<string.h>
struct node
{
	char a;
	int m;
}kuo[110];
bool b[110];
int main()
{
	char str1[110];
	scanf("%s",str1);
	memset(b,0,sizeof(b));
	int top=0;
	int len=strlen(str1);
	
	for(int i=0;i<len;i++)
	{
		if((str1[i]=='(')||(str1[i]=='['))
	    {
	    	kuo[top].a=str1[i];kuo[top].m=i;top++;
		}
		
		if((str1[i]==')')&&(kuo[top-1].a=='(')) {b[i]=1;b[kuo[top-1].m]=1;top--;}
		if((str1[i]==']')&&(kuo[top-1].a=='[')) {b[i]=1;b[kuo[top-1].m]=1;top--;}
	}
	for(int i=0;i<len;i++)
	{
		if(b[i]==1) printf("%s",str1[i]);
		else
		{
			if ((str1[i]=='(')||(str1[i]==')')) printf("()");
			if ((str1[i]=='[')||(str1[i]==']')) printf("[]");
		}
	}
	return 0;
 } 

P1030 求先序排列
1.先序排列,后续排列,中序排列是有一定规律顺序的
2.根据后续排列确定节点,然后到中序排列里面划分左右子树,写出find
3,每次输出被找到的那个根节点,递归左右子树,(l1,l2,r1,r2),这些的个数是改变的

#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
char s1[10];
char s2[10];
int len;
inline int find(char ch)
{
    for(int i=0;i<len;i++)
    {
        if(s1[i]==ch) return i;
    }
}
void dfs(int l1,int r1,int l2,int r2)
{
    int m=find(s2[r2]);
    cout<<s2[r2];
    if(m>l1) dfs(l1,m-1,l2,r2-r1+m-1);//第二个是节点个数 具有左子树,遍历左子树
    if(m<r1) dfs(m+1,r1,l2+m-l1,r2-1);
}
int main()
{
    cin>>s1;
    cin>>s2;
    len=strlen(s1);
    dfs(0,len-1,0,len-1);
}

自己构造出一棵树,然后中序遍历它

#include<iostream>
#include<cstring>

using namespace std;

char pre[10];//后序遍历
char mid[10];//前序遍历
int num[300];//字母对应的数字
char let[10];//数字对应的字母

struct node//结点
{
    int key;
    node * p=NULL;//父节点
    node * left=NULL;//左子
    node * right=NULL;//右子
};
typedef struct node * bNode;//结点指针

bNode tree_insert(bNode tree_root,int nkey)//二叉搜索树插入函数
{
    bNode z=new node,y=NULL,x=tree_root;
    z->key=nkey;
    while(x!=NULL)
    {
        y=x;
        if(nkey<x->key)x=x->left;
        else x=x->right;
    }
    z->p=y;
    if(y==NULL)tree_root=z;
    else if(nkey<y->key)y->left=z;
    else y->right=z;
    
    return tree_root;
}

void tree_preorder(bNode k)//前序遍历输出
{
    if(k==NULL)return;
    cout<<let[k->key];//key对应的字母
    tree_preorder(k->left);
    tree_preorder(k->right);
}

int main()
{
    bNode t1=NULL;
    cin>>mid>>pre;
    for(int i=0;mid[i]!='\0';i++)//建立字母与标号的双向联系
    {
        num[mid[i]]=i;
        let[i]=mid[i];
    }
    for(int i=strlen(pre)-1;i>=0;i--)//按颠倒顺序插入
    {
        t1=tree_insert(t1,num[pre[i]]);
    }
    tree_preorder(t1);
    return 0;
}

看不懂

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值