2014(未完)

第一题:啤酒和饮料(4' )

    啤酒每罐2.3元,饮料每罐1.9元。小明买了若干啤酒和饮料,一共花了82.3元。

    我们还知道他买的啤酒比饮料的数量少,请你计算他买了几罐啤酒。

#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;
/*一元二次方程问题,直接暴力*/
int main()
{
	for(int i=1;i<=35;i++)
	{
		for(int j=1;j<=43;j++)
		{
			if(23*i+19*j==823&&i<j)
			{
				cout<<i<<endl;
				break;
			}
		}
	}
	return 0;
}

第二题:切面条(5' )

    一根高筋拉面,中间切一刀,可以得到2根面条。
    如果先对折1次,中间切一刀,可以得到3根面条。
    如果连续对折2次,中间切一刀,可以得到5根面条。

    那么,连续对折10次,中间切一刀,会得到多少面条呢?

#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;
/*规律题 可以用纸模拟一下  
 分三部分  basic     左边圆弧部分      右边圆弧
		(永远是2) (pow(2,n-1))     (不断累加从1开始  累加前面的左边圆弧部分)
		面条的两端       (这两个合起来就是2的幂的和)
 */
int main()
{
	int res=0;
	for(int i=0;i<10;i++)
	{
		res+=pow(2,i);
	}
	res+=2;
	cout<<res<<endl;
	return 0;
}

第三题:李白打酒 (8' )

话说大诗人李白,一天,他提着酒壶,从家里出来,酒壶中有酒2斗。他边走边唱:
  无事街上走,提壶去打酒。
    逢店加一倍,遇花喝一斗。
  这一路上,他一共遇到店5次,遇到花10次,已知最后一次遇到的是花,他正好把酒喝光了。 

 请你计算李白遇到店和花的次序,可以把遇店记为a,遇花记为b。则:babaabbabbabbbb 就是合理的次序。像这样的答案一共有多少呢?请你计算出所有可能方案的个数(包含题目给出的)。 

#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;
/*递归思想*/
int sum=0;
int d(int a,int b,int f)//f表示酒
{
	if(a>0)
		d(a-1,b,f*2);//遇到店
	if(b>0)
		d(a,b-1,f-1);//遇到花
	if(a==0&&b==0&&f==1)sum+=1;
	//最后遇到花店那么遇到之前的酒是剩一斗的
	return sum;
}
int main()
{
	cout<<d(5,9,2)<<endl;
	//最后一次是花,所以10个花减最后1,就是9
	return 0;
}

第六题:奇怪的分式(11')

    上小学的时候,小明经常自己发明新算法。一次,老师出的题目是:
    1/4 乘以 8/5 
    小明居然把分子拼接在一起,分母拼接在一起,答案是:18/45 (参见图1.png)
    老师刚想批评他,转念一想,这个答案凑巧也对啊,真是见鬼!
    对于分子、分母都是 1~9 中的一位数的情况,还有哪些算式可以这样计算呢?
    请写出所有不同算式的个数(包括题中举例的)。
    显然,交换分子分母后,例如:4/1 乘以 5/8 是满足要求的,这算做不同的算式。

    但对于分子分母相同的情况,2/2 乘以 3/3 这样的类型太多了,不在计数之列!

#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
#include <cmath>
#define MIN 0.0000001
using namespace std;
/*又是一道暴力题,*/
int main()
{
	int cnt=0;
	for(int i=1;i<=9;i++)
		for(int j=1;j<=9;j++)
		{
			
			if(i==j)continue;//不能有1/1的情况
			for(int h=1;h<=9;h++)
				for(int t=1;t<=9;t++)
				{
					if(h==t)
						continue;
					double xx=(i*1.0/j)*(h*1.0/t);
					//这里*1.0转换类型
					double yy=(i*10.0+h)/(j*10.0+t);
					if(fabs(xx-yy)<MIN)//不可能完全相等,保证差不多就可以了
						cnt++;
				}
		}
	cout<<cnt<<endl;
	return 0;
}

第七题 三角填数


 

#include <iostream>
#include <cmath>
#include <cstdio>
#include <cstring>
using namespace std;
#define eps 10e-10
#define N 15
int a[N];
bool vis[N];
void dfs(int x)
{
	//遇到已知点跳过,点++
	if(x == 1 || x == 2 || x == 12){
		dfs(x+1);
		return ;
	}
	//当每个点都遍历完才执行下面的if
	if(x > 12)
	{
		int t[6];
		t[0] = a[1]+a[3] + a[6] + a[8];
		t[1] = a[1]+a[4] + a[7] + a[11];
		t[2] = a[2]+a[3] + a[4] + a[5];
		t[3] = a[2] + a[6] + a[9] + a[12];
		t[4] = a[8] + a[9] + a[10] + a[11];
		t[5] = a[12] + a[10] + a[7] + a[5];
		
		for(int i=1;i<6;++i)
		{
			if(t[i]!=t[i-1])return ;
		}//要求6条边都相等,不相等了就终止dfs()函数
		
		cout<<a[6]<<endl;//直接输出第6位的值。结束函数
		return ;
	}
	//首先执行给每个点填数
	for(int i=1;i<13;++i){
		if(!vis[i]){
			vis[i]=1;
			a[x]=i;
			dfs(x+1);
			vis[i] = 0;//上面x+1return回来然后执行该语句
			//把此点遍历记录消去,继续for循环
		}
	}
}

int main(){
	memset(vis,0,sizeof(vis));
	vis[1] = 1;
	a[1] = 1;
	vis[8] = 1;
	a[2] = 8;
	vis[3] = 1;
	a[12] =3;
	
	dfs(1);//从起点开始遍历
	
	return 0;
}

第八题 感冒蚂蚁

长100厘米的细长直杆子上有n只蚂蚁。它们的头有的朝左,有的朝右。 每只蚂蚁都只能沿着杆子向前爬,速度是1厘米/秒。 当两只蚂蚁碰面时,它们会同时掉头往相反的方向爬行。 这些蚂蚁中,有1只蚂蚁感冒了。并且在和其它蚂蚁碰面时,会把感冒传染给碰到的蚂蚁。 请你计算,当所有蚂蚁都爬离杆子时,有多少只蚂蚁患上了感冒。
输入:  n个蚂蚁    负左正右  第一个表示感冒的蚂蚁
输出:  有多少蚂蚁感冒
解题思路
首先明白两只蚂蚁碰撞之后掉头和穿行过去是一样的,可以把穿行看做碰撞后掉头了,然后两个蚂蚁交换了,而是哪一只蚂蚁对结果不影响。
那么,假如第一只感冒蚂蚁向右走,那么碰到所有想左走的都会被感染,而感染后的蚂蚁必定是向左走的,那么他会把左边向右走的都感染了。
向左走的也是这样。
所以 ans = 左边向右走的  + 右边向左走的 + 1(本身)。

当然还有特殊情况,第一只感染的向右走,右边的都在向右走,那么速度一样的话它不会感染其他所有,所以 ans = 1,相反也是。

#include <iostream>
#include <cmath>
#include <cstdio>
#include <cstring>
using namespace std;
#define eps 10e-10
#define N 15
struct Node
{
	int dis;
	int x;
	int num;
}a[10010];
bool cmp(Node a,Node b)
{
	return a.x<b.x;
}
int main()
{
	int n;
	while(cin>>n)
	{
		for(int i=0;i<n;i++)
		{
			int xx;
			cin>>xx;
			a[i].dis=xx<0?-1:1;//判断方向
			a[i].x=abs(xx);//换成绝对值
			a[i].num=i+1;//原始序号,用来确定第一个感冒蚂蚁的位置
		}
		sort(a,a+n,cmp);
		/*
		cout<<"======"<<endl;
		for(int i=0;i<n;i++)
		{
			cout<<a[i].dis<<" ";
			cout<<a[i].x<<" ";
			cout<<a[i].num<<" ";
			cout<<endl;
		}
		cout<<"===="<<endl;
		 */
		int tmp=0,l=0,r=0;
		for(int i=0;i<n;i++)
		{
			if(a[i].num==1)
			   tmp=i;//找到最开始感冒的蚂蚁
		}
		for(int i=0;i<tmp;i++)
		{
			if(a[i].dis==1)//感冒蚂蚁左边的所有往右的蚂蚁都会被感染
				l++;
		}
		//cout<<"tmp"<<tmp<<endl;
		for(int i=tmp+1;i<n;i++)//感冒蚂蚁右边的所有蚂蚁
		{
			if(a[i].dis==-1)r++;//如果这些蚂蚁走的方向都朝左,就会被感染
		}
		int ans=0;
		if((a[tmp].dis==1&&r==0)||(a[tmp].dis==-1 &&l==0))
			ans=1;
		else
			ans=l+r+1;
		cout<<ans<<endl;
	}
	return 0;
}
/*
 5
 -10 8 -20 12 25
 */

 第九题    地宫取宝   

X 国王有一个地宫宝库。是 n x m 个格子的矩阵。每个格子放一件宝贝。每个宝贝贴着价值标签。地宫的入口在左上角,出口在右下角。小明 地宫的入口 只能向右或向下行走。
走过某个格子时,如果那个格子中的宝贝价值比小明手中任意宝贝价值都大,小明就可以拿起它(当然,也可以不拿)。当小明走到出口时,如果他手中的宝贝恰好是k件,则这些宝贝就可以送给小明。小明有多少种不同的行动方案能获得这k件宝贝。
采用记忆化搜索。按自顶向下的顺序,每求解一个就将其解保存下来,以后再遇到就不必重新求解了。这个题用四维的数组存放搜索结果。当前值的查询次数记录下来,下次再到这个位置就不用重新搜索了。
https://paste.ubuntu.com/26442904/
记忆化搜索  经典例子  爬楼梯
https://paste.ubuntu.com/26442937/

最重要的东西就是一定会要一个数组或者其他的存储结构存储得到的子问题的解。这样就可以省很多时间,也就是典型的空间换时间。记忆化搜索的思想,它是解决重复计算,而不是重复生成。

#include <iostream>
#include <cmath>
#include <cstdio>
#include <cstring>
using namespace std;

#define N 1000000007
int ans;
int d[51][51][13][14];
int p[51][51];
int n,m,k;//k件宝贝
//v是手里当前宝贝的价值起始值为-1,因为可能图里有价值为0的
//num表示捡起来宝贝的个数
int dfs(int x,int y,int num,int v)
{
	
	if(d[x][y][num][v+1]!=-1)
	{
		return d[x][y][num][v+1];
	}//这个就是记忆化搜索
	int t=0;//t是遍历次数
	if(x==n-1&&y==m-1)//到达终点
	{
		if(p[x][y]>v)
		{
			if(num==k||num==k-1)t++;
		}
		else if(num==k)
			t++;
		return d[x][y][num][v+1]=t;
	}
	if(x+1<n)
	{
		if(p[x][y]>v)
		{
			t+=dfs(x+1,y,num+1,p[x][y]);
			t%=N;
			t+=dfs(x+1,y,num,v);
			t%=N;
		}
		else
		{
			t+=dfs(x+1,y,num,v);
			t%=N;
		}
	}
	if(y+1<m)
	{
		if(p[x][y]>v)
		{
			t+=dfs(x,y+1,num+1,p[x][y]);//捡
			t%=N;
			t+=dfs(x,y+1,num,v);//不捡
			t%=N;
		}
		else
		{
			t+=dfs(x,y+1,num,v);//不捡(没法捡)
			t%=N;
		}
	}
	d[x][y][num][v+1]=t;//把t赋给当前状态
	return d[x][y][num][v+1];
}

int main()
{
	
	while(cin>>n>>m>>k)
	{
		for(int i=0;i<n;i++)
		{
			for(int j=0;j<m;j++)
				cin>>p[i][j];
		}
		memset(d,-1,sizeof(d));
		d[0][0][0][0]=dfs(0,0,0,-1);
		//这里用的是0,而后面用的是-1,所以最后结果要用v+1
		cout<<d[0][0][0][0]<<endl;
	}
	return 0;
}

第十题 小朋友排队   

n 个小朋友站成一排。现在要把他们按身高从低到高的顺序排列,但是每次只能交换位置相邻的两个小朋友。每个小朋友都有一个不高兴的程度。开始的时候,所有小朋友的不高兴程度都是0。如果某个小朋友第一次被要求交换,则他的不高兴程度增加1,如果第二次要求他交换,则他的不高兴程度增加2(即不高兴程度为3),依次类推。当要求某个小朋友第k次交换时,他的不高兴程度增加k。请问,要让所有小朋友按从低到高排队,他们的不高兴程度之和最小是多少。如果有两个小朋友身高一样,则他们谁站在谁前面是没有关系的。
树状数组讲解
https://www.cnblogs.com/hsd-/p/6139376.html
树状数组线段树总结

http://blog.csdn.net/yexiaohhjk/article/details/51077545


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值