「思特奇杯-云上蓝桥-算法训练营」第2周

1.带分数

问题描述

100 可以表示为带分数的形式:100 = 3 + 69258 / 714。

还可以表示为:100 = 82 + 3546 / 197。

注意特征:带分数中,数字1~9分别出现且只出现一次(不包含0)。

类似这样的带分数,100 有 11 种表示法。

输入格式

从标准输入读入一个正整数N (N<1000*1000)

输出格式

程序输出该数字用数码1~9不重复不遗漏地组成带分数表示的全部种数。

注意:不要求输出每个表示,只统计有多少表示法!

#include<iostream>
#include<string.h>
using namespace std;
int a[10]={0};
Division(int m)//将数字分割 
{
	int t;	
	while(m)
	{
		t=m%10;
		if(t==0)//不会为零,不符合题意 
		{
			return 0;
		} 
		a[t]++;
		m=m/10; 
	}	
	return 1;
} 
int main()
{
	int i,k,j;//整数,分子,分母
	int number,ans=0,flag;
	cin>>number;
	for(i=1;i<number;i++)
	{
		for(j=1;j<=4938;j++)
		{
			memset(a,0,sizeof(a));//每次都应更新
			k=(number-i)*j; 
			if(Division(i)&&Division(j)&&Division(k))
			{
				flag=1;//每次都应更新
				for(int x=1;x<10;x++)//判断数字是否有重复的 
				{
					if(a[x]!=1)
					{
						flag=0;
						break;
					 } 
				}
				if(flag==1) ans++;
			}
		}
	}
	cout<<ans;
	return 0;
} 

2.李白打酒

题目描述

话说大诗人李白,一生好饮。幸好他从不开车。

一天,他提着酒壶,从家里出来,酒壶中有酒2斗。他边走边唱:

无事街上走,提壶去打酒。

逢店加一倍,遇花喝一斗。

这一路上,他一共遇到店5次,遇到花10次,已知最后一次遇到的是花,他正好把酒喝光了。

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

#include <iostream>
using namespace std;
 
int res = 0; 
 
//深搜 
void f(int dian, int hua, int jiu){
	if(dian == 0 && hua == 0 && jiu == 1){
		res ++;
	}
	if(dian > 0)
		f(dian-1, hua, jiu*2);
	if(hua > 0)
		f(dian, hua-1, jiu-1);
}
 
int main(int argc, char** argv) {
	
	f(5, 9, 2);
	cout << res << endl;
	return 0;
}

3.第39级台阶

题目描述:

    小明刚刚看完电影《第39级台阶》,离开电影院的时候,他数了数礼堂前的台阶数,恰好是39级!

    站在台阶前,他突然又想着一个问题:

    如果我每一步只能迈上1个或2个台阶。先迈左脚,然后左右交替,最后一步是迈右脚,也就是说一共要走偶数步。那么,上完39级台阶,有多少种不同的上法呢?

输出格式:

输出一个整数

#include <iostream>
using namespace std;
 
long long sum = 0;
 
void up(int n,int j)
{
	if(n == 39 && j % 2 == 0)//出口 
		sum ++;
	else if(n > 39)
		return; 
	else if(n == 39 && j % 2 != 0)
		return;
	else
	{
		up(n + 1, j + 1);
		up(n + 2, j + 1);
	}
}
 
int main()
{
	up(0, 0);
	cout << sum << endl;
	return 0;
}

4.穿越雷区

题目描述

已知的地图是一个方阵,上面用字母标出了A,B区,其它区都标了正号或负号分别表示正负能量辐射区。

例如:

A + - + -

- + - - +

- + + + -

+ - + - +

B + - + -

坦克车只能水平或垂直方向上移动到相邻的区。

数据格式要求:

输入第一行是一个整数n,表示方阵的大小, 4<=n<100

接下来是n行,每行有n个数据,可能是A,B,+,-中的某一个,中间用空格分开。

A,B都只出现一次。

要求输出一个整数,表示坦克从A区到B区的最少移动步数。

如果没有方案,则输出-1

#include <iostream>
#include <algorithm>
#include <queue>
#include <cstring>
using namespace std;
struct node
{
    int x,y;
    int step;
};
const int N = 110;
char g[N][N];
int vis[N][N];//标记是否走过
int n;
queue<node> q;
int dx[] = {-1,0,1,0},dy[] = {0,1,0,-1};
int bfs(int sx, int sy)
{
    node first;
    first.x = sx;
    first.y = sy;
    first.step = 0;
    q.push(first);
    vis[sx][sy] = 1;
    
    while (q.size())
    {
        node t = q.front();
        q.pop();
        if (g[t.x][t.y] == 'B')  return t.step;
        
        for (int i = 0 ; i < 4 ; i ++)
        {
            int x1 = t.x + dx[i] , y1 = t.y + dy[i];
            if (x1 < 0 || x1 >= n || y1 < 0 || y1 >= n || vis[x1][y1] == 1 || g[x1][y1]==g[t.x][t.y] ) continue;
            
            node next;
            next.x = x1;
            next.y = y1;
            next.step = t.step + 1;
            q.push(next);
            vis[x1][y1] = 1;
        }
    }
   return -1;
  
}
int main()
{
    cin >> n;
    int sx,sy;
    for (int i = 0 ; i < n ; i ++)
       for (int j = 0 ; j < n ; j ++)
       {
           cin >> g[i][j];
           if (g[i][j] == 'A')
           {
               sx = i;
               sy = j;
           }
       }
          
    cout << bfs(sx,sy) << endl;
    return 0;
}

5.迷宫

题目描述

下图给出了一个迷宫的平面图,其中标记为 1 的为障碍,标记为 0 的为可 以通行的地方。

010000

000100

001001

110000

迷宫的入口为左上角,出口为右下角,在迷宫中,只能从一个位置走到这 个它的上、下、左、右四个方向之一。 对于上面的迷宫,从入口开始,可以按DRRURRDDDR 的顺序通过迷宫, 一共 10 步。其中 D、U、L、R 分别表示向下、向上、向左、向右走。 对于下面这个更复杂的迷宫(30 行 50 列),请找出一种通过迷宫的方式, 其使用的步数最少,在步数最少的前提下,请找出字典序最小的一个作为答案。 请注意在字典序中D<L<R<U。(如果你把以下文字复制到文本文件中,请务 必检查复制的内容是否与文档中的一致。在试题目录下有一个文件 maze.txt, 内容与下面的文本相同)

广度优先搜索

#include <iostream>
#include <string>
#include <queue>

using namespace std;

int maze[35][55];
int dir[][2] = { { 1, 0 }, { 0, -1 }, { 0, 1 }, { -1, 0 } };
char d[4] = { 'D', 'L', 'R', 'U' };
int cnt = 0x3f3f3f3f;
bool vis[35][55];

struct node{
	int x;
	int y;
	string rode;
	int step;
	node(int xx, int yy, string ss, int tt)
	{
		x = xx;
		y = yy;
		rode = ss;
		step = tt;
	}
};

bool check(int x, int y){
	if (x <= 30 && x >= 1 && y <= 50 && y >= 1){
		return true;
	}
	return false;
}

void bfs(int x, int y, string s, int num){
	queue<node> q;
	q.push(node(x, y, s, num));
	while (!q.empty()){
		node now = q.front();
		q.pop();

		vis[now.x][now.y] = true;

		if (now.x == 30 && now.y == 50){
			if (now.step < cnt){
				cnt = now.step;
				cout << now.step << endl;
				cout<< now.rode << endl;
				vis[now.x][now.y] = false;
			}
			continue;
		}

		for (int i = 0; i < 4; i++){
			int tx = now.x + dir[i][0];
			int ty = now.y + dir[i][1];

			if (maze[tx][ty] == 0 && !vis[tx][ty] && check(tx, ty)){
				q.push(node(tx, ty, now.rode + d[i], now.step + 1));
			}
		}
	}
}

int main(){

	for (int i = 1; i <= 30; i++){
		for (int j = 1; j <= 50; j++){
			maze[i][j] = getchar()-'0';
		}
		getchar();
	}

	bfs(1, 1, "", 0);

	return 0;
}

6.跳马

问题描述:

中国象棋半张棋盘如图1所示。马自左下角(0,0)向右上角(m,n)跳。规定只能往右跳,不准往左跳。比如图1中所示为一种跳行路线,并将路径总数打印出来。

广度搜索

#include<bits/stdc++.h>
using namespace std;
const int N=1e5+5;
typedef long long ll;
int vis[10][10];//存当前点是否到过
int dir[8][2]={{1,2},{1,-2},{2,-1},{2,1},{-2,1},{-2,-1},{-1,-2},{-1,2}};//存八个方向
void dfs(int a,int b,int c,int d){
    vis[a][b]=1;
    queue<pair<pair<int,int>,int> > q;
    q.push({{a,b},0});
    while(!q.empty()){
        pair<pair<int,int>,int> tem=q.front();//编译器不支持auto
        q.pop();
        for(int i=0;i<=7;i++){
            int x=tem.first.first+dir[i][0],y=tem.first.second+dir[i][1],step=tem.second;
            if(x==c&&y==d){
                printf("%d\n",step+1);
                return;
            }
            if(x>=1&&x<=8&&y>=1&&y<=8&&!vis[x][y]){
                q.push({{x,y},step+1});
            }
        }
    }
}
int main(){
    int a,b,c,d;
    scanf("%d%d%d%d",&a,&b,&c,&d);
    if(a==c&&b==d){
        printf("0\n");
        return 0;
    }
    dfs(a,b,c,d);
    return 0;
}

7.路径之谜

小明冒充X星球的骑士,进入了一个奇怪的城堡。

城堡里边什么都没有,只有方形石头铺成的地面。

假设城堡地面是 n x n 个方格。【如图1.png】所示。

按习俗,骑士要从西北角走到东南角。

可以横向或纵向移动,但不能斜着走,也不能跳跃。

每走到一个新方格,就要向正北方和正西方各射一箭。

(城堡的西墙和北墙内各有 n 个靶子)

同一个方格只允许经过一次。但不必做完所有的方格。

如果只给出靶子上箭的数目,你能推断出骑士的行走路线吗?

有时是可以的,比如图1.png中的例子。

本题的要求就是已知箭靶数字,求骑士的行走路径(测试数据保证路径唯一)

输入:

第一行一个整数N(0<N<20),表示地面有 N x N 个方格

第二行N个整数,空格分开,表示北边的箭靶上的数字(自西向东)

第三行N个整数,空格分开,表示西边的箭靶上的数字(自北向南)

#include <iostream>
#include <stdlib.h>
using namespace std;
 
int arr[22][22]={0}; //(i-1)*N + j - 1 
int ans[410];
int count_ans=0;
int N;
 
 bool dfs(int i, int j)
 {
 	if(i == N && j == N)
 	{
 		//判断是否所有箭都中了
 		int flag=0;
		for(int k=1; k<=N; k++)
		{
			flag+=arr[k][0];
			flag+=arr[0][k];
		 	if(flag>2)
		 		break;
		}
		//已经找到这条路了 
		if(flag == 2) 
		{
			for(int k=0; k<count_ans; k++)
				cout<<ans[k]<<" ";
			cout<<N*N-1; 
			return true;
		} 
		else
			return false;
	}
	
	if(i<1 || i>N || j<1 || j>N)//剪枝3:超出范围 
		return false; 
	if(arr[i][j] != 0)//剪枝1:走过
		return false;
	if(arr[i][0] == 0 || arr[0][j] == 0)//剪枝2:箭不够了
		return false;
	
 	arr[i][j]=1;//设为旧点,拔出箭 ,放入答案栈 
 	arr[i][0]--;
 	arr[0][j]--;
 	ans[count_ans++]= (i-1)*N + j - 1 ;
 	if(dfs(i+1,j)||dfs(i-1,j)||dfs(i,j+1)||dfs(i,j-1)) 
 		return true;
 	count_ans--;//复原 
 	arr[i][0]++;
 	arr[0][j]++;
 	arr[i][j]=0;
 	return false;
 }
 
int main()
{
	cin>>N;
	for(int i=0; i<N; i++)
		cin>>arr[0][i+1];
	for(int i=0; i<N; i++)
		cin>>arr[i+1][0];
 
	dfs(1,1);
 
	return 0;
}

​​​​​​​8.未名湖边的烦恼

问题描述

  每年冬天,北大未名湖上都是滑冰的好地方。北大体育组准备了许多冰鞋,可是人太多了,每天下午收工后,常常一双冰鞋都不剩。

  每天早上,租鞋窗口都会排起长龙,假设有还鞋的m个,有需要租鞋的n个。现在的问题是,这些人有多少种排法,可以避免出现体育组没有冰鞋可租的尴尬场面。(两个同样需求的人(比如都是租鞋或都是还鞋)交换位置是同一种排法)

#include<bits/stdc++.h>

using namespace std;

int res(int m, int n){
	if(m < n){
		return 0;	//无鞋可借 
	}
	if(n == 0){
		return 1;//都有鞋穿了 
	} 
	return  res(m - 1, n) + res(m, n - 1);
} 

int main() {
	int m, n;
	cin >> m >> n;
	int r = res(m, n);
	cout << r;
	return 0;
}

9.大臣的旅费

问题描述

很久以前,T王国空前繁荣。为了更好地管理国家,王国修建了大量的快速路,用于连接首都和王国内的各大城市。

为节省经费,T国的大臣们经过思考,制定了一套优秀的修建方案,使得任何一个大城市都能从首都直接或者通过其他大城市间接到达。同时,如果不重复经过大城市,从首都到达每个大城市的方案都是唯一的。

J是T国重要大臣,他巡查于各大城市之间,体察民情。所以,从一个城市马不停蹄地到另一个城市成了J最常做的事情。他有一个钱袋,用于存放往来城市间的路费。

聪明的J发现,如果不在某个城市停下来修整,在连续行进过程中,他所花的路费与他已走过的距离有关,在走第x千米到第x+1千米这一千米中(x是整数),他花费的路费是x+10这么多。也就是说走1千米花费11,走2千米要花费23。

J大臣想知道:他从某一个城市出发,中间不休息,到达另一个城市,所有可能花费的路费中最多是多少呢?

输入格式

输入的第一行包含一个整数n,表示包括首都在内的T王国的城市数

城市从1开始依次编号,1号城市为首都。

接下来n-1行,描述T国的高速路(T国的高速路一定是n-1条)

每行三个整数Pi, Qi, Di,表示城市Pi和城市Qi之间有一条高速路,长度为Di千米。

#include<iostream>
#include<vector>
#include<cstring>

using namespace std;

const int N = 1e5 + 10;

struct Edge {
  int f, t, v;
}edge[N];                                                                                           
int n;
int cnt;
int value;
int maxValue,maxValueIndex;
vector<int> vis;
vector<int> occurrences;

void dfs(int edgeNum)
{
  bool flag = false;
  vis[edgeNum] = 1;
  ++occurrences[edge[edgeNum].f];
  ++occurrences[edge[edgeNum].t];
  value += edge[edgeNum].v;
  for(int i = 1; i <= cnt; ++i)
  {
    if((edge[edgeNum].f == edge[i].f || edge[edgeNum].f == edge[i].t || edge[edgeNum].t == edge[i].f || edge[edgeNum].t == edge[i].t) && vis[i] == 0 && occurrences[edge[i].f] < 2 && occurrences[edge[i].t] < 2)
    {
      flag = true; 
      dfs(i);
    }
  }
  if(!flag)
  {
    if(value > maxValue)
    {
      maxValue = value;
      maxValueIndex = edgeNum;
    }
  }
  vis[edgeNum] = 0;
  --occurrences[edge[edgeNum].f];
  --occurrences[edge[edgeNum].t];
  value -= edge[edgeNum].v;
}
int main()
{
  cin >> n;
  vis = vector<int>(n + 10, 0);
  occurrences = vector<int>(n + 10, 0);

  cnt = 0;
  int begin, end, v;
  for(int i = 0; i < n - 1; ++i)
  {
    cin >> begin >> end >> v;
    edge[++cnt].f = begin;
    edge[cnt].t = end;
    edge[cnt].v = v;
  }
  maxValue = 0;
  dfs(1);
  dfs(maxValueIndex);
  cout << (maxValue * maxValue + 21 * maxValue) / 2 << endl;
  return 0;
}

10.2n皇后问题

Description

给定一个n*n的棋盘,棋盘中有一些位置不能放皇后。现在要向棋盘中放入n个黑皇后

和n个白皇后,使任意的两个黑皇后都不在同一行、同一列或同一条对角线上,任意的两

个白皇后都不在同一行、同一列或同一条对角线上。问总共有多少种放法?n小于等于8。

Input

输入的第一行为一个整数n,表示棋盘的大小。

接下来n行,每行n个0或1的整数,如果一个整数为1,表示对应的位置可以放皇后,

如果一个整数为0,表示对应的位置不可以放皇后。

#include<cmath>  
#include<iostream>  
using namespace std; 
 
const int maxn = 10;  
int n;  
int map_Q[maxn][maxn];  
int posb[maxn]={0};  
int posw[maxn]={0};  
int ans;   
 
bool checkw( int cur) //检查函数
{  
    for( int i = 1; i < cur; i++)  
        if( posw[i] == posw[cur] || abs(i-cur) == abs(posw[i]-posw[cur]))  
            return false;  
    return true;  
}   
 
bool checkb( int cur)  //检查函数
{  
    for( int i = 1; i < cur; i++)  
        if( posb[i] == posb[cur] || abs(i-cur) == abs(posb[i]-posb[cur]))  
            return false;  
    return true;  
}  
 
void dfs_white( int cur)  
{  
    if( cur == n+1)  //白皇后也全部放完,次数+1
    {  
        ans++;  
      }
    for( int i = 1; i <= n; i++)  
    {  
        if( posb[cur] == i) //表示第cur列的第i行位置已经被黑皇后占用,
            continue;        //结束当前循环,i+1
        if( map_Q[cur][i] == 0)  //再判断前提条件是否成立
            continue;  
        posw[cur] = i;    //尝试把第cur列的白皇后放在第i行上
        if( checkw(cur))   //判断能否放置白皇后
            dfs_white(cur+1);  //递归
    }  
}  
  
void dfs_black( int cur)  
{  
    if( cur == n+1)  //当黑皇后处理完时,再处理白皇后
    {  
        dfs_white(1);  
    }  
    for( int i = 1; i <= n; i++)  
    {  
       if( map_Q[cur][i] == 0)  //如果第cur列第i行满足放皇后的前提条件即 mp[cur][i] == 1
            continue;  //如果不满足,则结束当前循环,进行下一次循环即i+1。
         posb[cur] = i;     //就尝试把第cur列的黑皇后放在第i行上
        if( checkb(cur))   //然后判断该尝试是否成立,如成立,则进行递归,如不成立,则尝试把当前列的黑皇后放在下一行(i+1行)上。
            dfs_black(cur+1);  //递归
    }  
}  
  
int main()  
{     
   cin>>n;
   for( int i = 1; i <= n; i++)   //定义棋盘
       for( int j = 1; j <= n; j++)  
           cin>>map_Q[i][j];    
   ans = 0;  
   dfs_black(1);    //先把黑皇后放在第一列
   cout<<ans<<endl; 
   
    return 0;  
}  

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值