顺序题单之外的搜索 1

P1192
台阶问题,每次走,都是前面n种走法之和,emm你得先走到n种,不然就是你走到此之前的种类,记得初始值是1

#include<iostream>
#include<math.h>
using namespace std;
int f[100002];
int main()
{
	int m,n;
	cin>>m>>n;
	f[0]=1;
	for(int j=1;j<=m;j++)
	{
		for(int i=1;i<=min(j,n);i++)
		{
			f[j]+=f[j-i];
			f[j]%=100003;
		}
		
	}
		
		cout<<f[m];
		return 0;
 } 
 

P1025
这应该是搜索吧,每一次搜索增加一,然后到三的时候,就看和是不是这个数,如果是的话答案就增加1
有一个不得不做的剪枝就是枚举当前划分所用分数时应该从last(上次划分所用分数)枚举到sum+i*(k-cur)<=n为止,因为之后划分的分数一定大于或等于当前划分所用分数。

#include<cstdio>

int n,k,cnt;

void dfs(int last,int sum,int cur)
{
    if(cur==k)
    {
        if(sum==n) cnt++;
        return;
    }
    for(int i=last;sum+i*(k-cur)<=n;i++)//剪枝,只用枚举到sum+i*(k-cur)<=n为止
        dfs(i,sum+i,cur+1);
}

int main()
{
    scanf("%d%d",&n,&k);
    dfs(1,0,0);
    printf("%d",cnt);
}

f[i][x]表示i分成x个非空的数的方案数
显然 i<x 时 f[i][x]=0 , i=x 时 f[i][x]=1;

其余的状态,我们分情况讨论:

①有1的 ②没有1的

第一种情况,方案数为 f[i-1][x-1]

第二种情况,方案数为 f[i-x][x] (此时 i 必须大于 x)

所以,状态转移方程为: f[i][x]=f[i-1][x-1]+f[i-x][x],这其实就是背包的思想啊

#include<iostream>
using namespace std;
int f[201][7]; 
int main()
{
  int m,n;
  cin>>m>>n;
  for(int i=1;i<=m;i++)
  {
  	f[i][1]=1;
  	f[i][0]=1;
  }
  for(int i=2;i<=n;i++)
  {
  	f[0][i]=0;
  	f[1][i]=0;
  }
  for(int i=2;i<=m;i++)//m个物品
  {
  	for(int j=2;j<=n;j++)//容积是三
  	{
  		if(i>j)
  		f[i][j]=f[i-1][j-1]+f[i-j][j];
	    else
	    f[i][j]=f[i-1][j-1];
	  }
  }
  cout<<f[m][n];
}
 

P1057
就想结尾,传到他手里的前提是前面一步是他的左边或者右边
所以初始化是在自己手上,数组应该是传的次数和球所在的位置,

#include<iostream>
using namespace std;
int f[31][31]={1};
int main()
{
	int m,n;//m是次数,n 是人数 
	cin>>n>>m;
	
	for(int i=1;i<=m;i++)
	{
		for(int j=0;j<n;j++)
		{
			f[i][j]=f[i-1][(j+1)%n]+f[i-1][(j-1+n)%n];
		}
	}
	cout<<f[m][0];
}

中心思想是判断走了多少步,也就是传了多少次球,然后在这样下面,每个人对应的次数是多少,初始化小蛮自己是1

P1135
奇怪的电梯
两种做法,一种是DP,一种是广搜

首先来看DP,
一个数组里面放按的数量,和当前所在的位置,如何控制顺序,依靠做标记,所以就是dp[到这楼要几次][楼层数]=有没有去过
初始化就是在一楼(说不定目标也在1楼呢,特判要注意,按键数目是1
接下去两重循环,按几次(不好说就往大了定),和每一次上面的的可能
你到过一个楼层,因为需要最小的,所以不可能再次到达,所以就不会再经历,所以只要根据两者之间关系判断是不是B就可以

#include<iostream>
using namespace std;
int a[202],f[202][202]; 
int main()
{
	int N,A,B,iflag=0;
	cin>>N>>A>>B;
	for(int i=1;i<=N;i++)
	{
		cin>>a[i];
	}
	if(A==B)
	{
		cout<<0;
		return 0;
	}
	f[0][A]=1;
	for(int i=0;i<=200;i++)
	 for(int j=1;j<=N;j++)
	 {
	 	if(f[i][j])
	 	{
	 		if(j+a[j]<=N)
	 		f[i+1][j+a[j]]=1;
	 		if(j-a[j]>=1)
	 		f[i+1][j-a[j]]=1;
	 		if(f[i+1][B]==1)
	 		{cout<<i+1;
	 		iflag=1;
	 		return 0;
			 }
	 		
		 }
	 }
	 if(iflag==0)
	 cout<<-1;
	 return 0;
	
}

第二种是广搜,应该就是先把a入队,然后通过加减来标志能到的,入队,再一次广搜,直到找到,每一次cnt++

#include<iostream>
#include<queue>
using namespace std;
int N,A,B;
int visited[202],cnt=0,a[202],flag;
queue<int>Q;
queue<int>P;
void bfs(int o,int b)
{
	int dx,dy;
	while(!Q.empty() )
	{
	    if(dx==B||dy==B)
		{	cout<<cnt;
		    flag=1;
		    return ;
		}	
		if(Q.front() +P.front() <=N)
		{
			dx=Q.front() +P.front() ;
			if(!visited[dx])
			{
				visited[dx]=1;
				Q.push(dx);
				P.push(a[dx]);
				cnt++;
			}
		}
		if(Q.front() -P.front() >=1)
		{
			dy=Q.front() -P.front() ;
			if(!visited[dy])
			{
				visited[dy]=1;
				Q.push(dy); 
				P.push(a[dy]);
				cnt++;
			}
		}
		Q.pop() ;
		P.pop() ;
		
		
	}
	if(flag==0)
	cout<<-1;
	 
}
int main()
{
	cin>>N>>A>>B;
	if(A==B)
	{cout<<0;
	return 0;
	}
	for(int i=1;i<=N;i++)
	{
		cin>>a[i];
	}
	visited[A]=1;
	Q.push(A); 
	P.push(a[A]);
	bfs(A,a[A]);
	
 } 
 

还可以用floyed,震惊我,确实相当于由边连起来的点,这样子存起来之后,不断进行拉伸

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int dis[201][201],n,a,b,x;
int main()
{
    scanf("%d%d%d",&n,&a,&b);
    for(int i=1;i<=n;i++)
        for(int j=1;j<i;j++)
            dis[i][j]=dis[j][i]=1e8;
    for(register int i=1;i<=n;i++)
    {
        scanf("%d",&x);
        if(i+x<=n) dis[i][i+x]=1;
        if(i-x>=1) dis[i][i-x]=1;
    }
    for(int k=1;k<=n;++k)
        for(int i=1;i<=n;++i)
            for(int j=1;j<=n;++j)
                if(dis[i][j]>dis[i][k]+dis[k][j])
                	dis[i][j]=dis[i][k]+dis[k][j];
    if(dis[a][b]<1e8) printf("%d",dis[a][b]);
    else printf("-1");
    return 0;
}

P1090
他每一次合并之后消耗的体力还会留下来,所以相当于有一部分数字是在一直被利用的,斯怎么有点杨辉三角
应该先排序,然后把最少的合并,合并完以后插入,用优先队列:priority_queue<int,vector,greater >

#include<iostream>
#include<queue>
using namespace std;
int a[10086]; 
priority_queue<int ,vector<int>,greater<int> >qu;
int main()
{
	int m,x,y,ans=0;
	cin>>m;
	for(int i=1;i<=m;i++)
	{
		cin>>a[i];
		qu.push(a[i]);
	}
	for(int i=1;i<=m-1;i++)
	{
		x=qu.top();
		qu.pop();
		x+=qu.top(); 
		ans+=x;
		qu.pop();
		qu.push(x);
		
	}
	
	cout<<ans;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值