杂项 杂项 杂项 杂项 杂项

 搜索--广搜--最短路径长度--最短路径路径--最短路径最小字典序

抓住那头牛

农夫约翰被通知,他的一只奶牛逃逸了!所以他决定,马上出发,尽快把那只奶牛抓回来.

    他们都站在数轴上.约翰在N(0≤N≤100000)处,奶牛在K(0≤K≤100000)处.约翰有

两种办法移动,步行和瞬移:步行每秒种可以让约翰从x处走到x+1或x-1处;而瞬移则可让他在1秒内从x处消失,在2x处出现.然而那只逃逸的奶牛,悲剧地没有发现自己的处境多么糟糕,正站在那儿一动不动.

    那么,约翰需要多少时间抓住那只牛呢?

输入格式

* Line 1: Two space-separated integers: N and K

    仅有两个整数N和K.

输出格式

* Line 1: The least amount of time, in minutes, it takes for Farmer John to catch the fugitive cow.

    最短的时间.

样例

输入样例:

5 17
Farmer John starts at point 5 and the fugitive cow is at point 17.

输出样例:

4
OUTPUT DETAILS:

The fastest way for Farmer John to reach the fugitive cow is to
move along the following path: 5-10-9-18-17, which takes 4 minutes.

 广搜 - -队列

每次取队头元素出队列,对于该队头节点,可能就是要求的节点,成功,退出;也可能不是,不是的话,利用该队头元素扩展与该节点有边相连且没有被访问的节点,将新的节点入队 ,直到队为空,所有图中相连的节点都被访问过。

devC++

//#include<bits/stdc++.h> 
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <algorithm>
#include <queue>
#include <stack>
#include <map>
#include <vector>
#include <cstring>//memset
#include <string>
using namespace std;
//const int maxn = 1e8;
//求素数
bool IsPrime(int m){
	if(m == 2)
		return true;
	int tmp = sqrt(m);
	for(int i = 2;i <= tmp;i++)
		if(m%i == 0)
			return false;
	return true;
}
//求最大公因数
int gcd_wx(int a,int b){
	while(a!=b)
	{
		if(a>b)
			a = a-b;
		else
			b = b-a;
	}
	return a;
}
//求闰年
bool leapYear(int y){
	if(y%400 == 0)
		return true;
	if(y%4 == 0&& y%100!= 0)
		return true;
	return false;
}
//方向数组
int dx[4] = {0,0,1,-1};
int dy[4] = {1,-1,0,0};
//N表示起点,K表示终点
int N,K;
const int maxn = 1e5;
int visited[maxn+10];
//结构体存储节点信息
struct Step{
	int x;//存储位置
	int steps;//第steps步走到位置x
    //结构体初始化函数
	Step(int xx,int s):x(xx),steps(s){
	}
};
queue<Step>q;//STL队列,取队头元素.front(),.pop()队头出元素,.push(元素)队尾插入元素
int main(){
	cin>>N>>K;
	memset(visited,0,sizeof(visited));//初始化标记数组
    //初始化queue第0步走到位置N处
	q.push(Step(N,0));
	visited[N] = 1;//标记已走过
    //队非空
	while(!q.empty()){
		Step s = q.front();//取队头元素,遍历与队头元素相连的点,遍历过后该点出队
		if(s.x == K){
			//到达目的地,输出答案 
			cout<<s.steps<<endl;
			return 0; 
		}
		else{
			int ax = s.x-1;//ax存储下一步的位置
			int as = s.steps+1;//as存储下一步的步数
            //下一步符合要求则入队并标记,不符合则跳过
			if(ax>=0&&!visited[ax]){
				q.push(Step(ax,as));
				visited[ax] = 1;
			}
			ax = s.x+1;
			if(ax<=maxn&&!visited[ax]){
				q.push(Step(ax,as));
				visited[ax] = 1;
			}
			ax = s.x*2;
			if(ax<=maxn&&!visited[ax]){
				q.push(Step(ax,as));
				visited[ax] = 1;
			}
		}
		q.pop();//该点出队
	}
	return 0;
}

迷宫问题

迷宫问题

Time Limit: 1000MS        Memory Limit: 65536K
Description

定义一个二维数组:

int maze[5][5] = {

    0, 1, 0, 0, 0,

    0, 1, 0, 1, 0,

    0, 0, 0, 0, 0,

    0, 1, 1, 1, 0,

    0, 0, 0, 1, 0,

};

它表示一个迷宫,其中的1表示墙壁,0表示可以走的路,只能横着走或竖着走,不能斜着走,要求编程序找出从左上角到右下角的最短路线。

Input

一个5 × 5的二维数组,表示一个迷宫。数据保证有唯一解。

Output

左上角到右下角的最短路径,格式如样例所示。

Sample Input

0 1 0 0 0
0 1 0 1 0
0 0 0 0 0
0 1 1 1 0
0 0 0 1 0
Sample Output

(0, 0)
(1, 0)
(2, 0)
(2, 1)
(2, 2)
(2, 3)
(2, 4)
(3, 4)
(4, 4)

//#include<bits/stdc++.h> 
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <algorithm>
#include <queue>
#include <stack>
#include <map>
#include <vector>
#include <cstring>//memset
#include <string>
using namespace std;
//const int maxn = 1e8;
bool IsPrime(int m){
	if(m == 2)
		return true;
	int tmp = sqrt(m);
	for(int i = 2;i <= tmp;i++)
		if(m%i == 0)
			return false;
	return true;
}
int gcd_wx(int a,int b){
	while(a!=b)
	{
		if(a>b)
			a = a-b;
		else
			b = b-a;
	}
	return a;
}
bool leapYear(int y){
	if(y%400 == 0)
		return true;
	if(y%4 == 0&& y%100!= 0)
		return true;
	return false;
}
int dx[4] = {0,0,1,-1};
int dy[4] = {1,-1,0,0};

struct Step{
	int x;
	int steps;//第steps步走到位置x
	Step(int xx,int s):x(xx),steps(s){
	}
};
queue<Step>q;
struct node{
	//输出最短路径的步数和路径 
	int x;
	int y;
	int front;//记录上一个节点
	int steps; 
	node():x(-1),y(-1),front(-1),steps(0){
	}
	node(int xx,int yy,int ff,int s):x(xx),y(yy),front(ff),steps(s){
	}
}; 
struct node que[30];
int mp[6][6];//存放迷宫地图  
int visited[6][6];//标记 
int path[30];//存放路径
int main(){
	for(int i = 0;i < 5;i++)
		for(int j = 0;j < 5;j++)
			cin>>mp[i][j];
	memset(visited,0,sizeof(visited)) ;
	que[0] = node (0,0,-1,0);
	int head,tail;
	head = 0;
	tail = 1;
	while(head < tail){
		struct node s = que[head];//取队头元素 
		if(s.x== 4&&s.y == 4){
			//找到路径
			//cout<<"最短路径长度是"<<s.steps<<endl; 该语句不注释的话就是输出最短路径长度 
			int k = 0;//k从0开始 
			while(k<30){//外层死循环 
				path[k] = s.front;
				s = que[s.front];
				if(path[k] == 0)break;//内层退出 
				k++;
			} 
			while(k>=0){
				cout<<"("<<que[path[k]].x<<","<<que[path[k]].y<<")"<<endl;
				k--; 
			}
			cout<<"(4,4)"<<endl;
			//cout<<"最短路径长度是"<<s.steps<<endl;//若在此处还是用s输出最短路径 是错误的,s已经变化了 
			return 0;
		}
		else{
			//遍历相连的所有点 
			for(int i = 0;i < 4;i++){
				int ax = s.x+dx[i];
				int ay = s.y+dy[i];
				if(ax>=0&&ax<=4&&ay>=0&&ay<=4&&!visited[ax][ay]&&mp[ax][ay]==0){
					que[tail++] = node(ax,ay,head,s.steps+1);
					visited[ax][ay] = 1;
				}
			}
		}
		head++;//删去队头元素 
	}
	return 0;
}

最短路径问题

三行代码

floyd

小蓝学习了最短路径之后特别高兴,他定义了一个特别的图,希望找到图中的最短路径。
小蓝的图由2021 个结点组成,依次编号1 至2021。
对于两个不同的结点a, b,如果a 和b 的差的绝对值大于21,则两个结点之间没有边相连;
如果a 和b 的差的绝对值小于等于21,则两个点之间有一条长度为a 和b 的最小公倍数的无向边相连。
例如:结点1 和结点23 之间没有边相连;结点3 和结点24 之间有一条无向边,长度为24;
结点15 和结点25 之间有一条无向边,长度为75。
请计算,结点1 和结点2021 之间的最短路径长度是多少。
提示:建议使用计算机编程解决问题

最短路径模板

dijkstra从点A到终点K的最短路径长度,所有点构成的集合U,分为两类,一类是已经确定的最短路径的点集合V,一类是还没有确定最短路径的点集合U-V,这两种点可以用visited标记数组进行标记--初始,只有一个点A在V中,记录最短路径长度是0---每次,枚举所有的U-V的点,将到V中最短的点加入,更新最短路径长度,直到加入的点是K,中间要用数组存储每个点的直接前驱便于输出最短路径

//#include<bits/stdc++.h> 
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <algorithm>
#include <queue>
#include <stack>
#include <map>
#include <vector>
#include <cstring>//memset
#include <string>
using namespace std;
const int maxn = 1e8;
bool IsPrime(int m){
	if(m == 2)
		return true;
	int tmp = sqrt(m);
	for(int i = 2;i <= tmp;i++)
		if(m%i == 0)
			return false;
	return true;
}
int gcd_wx(int a,int b){
	while(a!=b)
	{
		if(a>b)
			a = a-b;
		else
			b = b-a;
	}
	return a;
}
bool leapYear(int y){
	if(y%400 == 0)
		return true;
	if(y%4 == 0&& y%100!= 0)
		return true;
	return false;
}
int dx[4] = {0,0,1,-1};
int dy[4] = {1,-1,0,0};

struct Step{
	int x;
	int steps;//第steps步走到位置x
	Step(int xx,int s):x(xx),steps(s){
	}
};
queue<Step>q;
struct node{
	//输出最短路径的步数和路径 
	int x;
	int y;
	int front;//记录上一个节点
	int steps; 
	node():x(-1),y(-1),front(-1),steps(0){
	}
	node(int xx,int yy,int ff,int s):x(xx),y(yy),front(ff),steps(s){
	}
}; 
int mp[2025][2025];//存放迷宫地图  
int visited[2025];//标记 
int path[2025];//存放路径
int dis[2025];
int main(){
	for(int i = 1;i <= 2021;i++)
		for(int j = 1;j <= 2021;j++)
			{
				if(i == j)
					mp[i][j] = maxn;
				else
					if(abs(i-j)<=21)
						mp[i][j] = i*j/gcd_wx(i,j);
					else
						mp[i][j] = maxn;
			} 
	for(int i = 1;i <= 2021;i++)
		{
			dis[i] = mp[1][i];
			path[i] = 1;
		}
	memset(visited,0,sizeof(visited));
	//外层循环n-1次--n表示总的点数,这里是2021
	for(int times = 1;times < 2021;times++){
		int indexMin = -1,disMin;
		disMin = dis[2];
		for(int i = 3;i <=2021;i++){//找U-V中最小的dis 
			if(!visited[i]&&(indexMin == -1||disMin>dis[i])){
				indexMin = i;
				disMin = dis[i];
			}
		}
		visited[indexMin] = 1;
		for(int i = 3;i <= 2021;i++)
			{
				if(!visited[i]&&dis[i] >dis[indexMin]+mp[indexMin][i])
					{
						dis[i] = dis[indexMin]+mp[indexMin][i];
						path[i] = indexMin;
					}
			} 
	} 
	cout<<dis[2021]<<endl;
	int k = 2021;
	cout<<2021<<" ";
	int ans = 1;
	while(true){
		if(ans%10 == 0)cout<<endl;
		cout<<path[k]<<" ";
		ans++;
		if(path[k] == 1)break;
		k = path[k];
	}
	cout<<"\n从1到2021一共有"<<ans<<"个数"<<endl; 
	return 0;
}

floyd则是三重循环,枚举两个点(路径的两端),再在路径中间枚举所有点,找最短路径(可以看作动态规划)--暴力

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];//path[i][j] = k;//记录路径数组}

#include <iostream>
#include <cmath>
using namespace std;
const int MAX = 1e9;
int mp[2025][2025];
int __gcd(int a, int b) {
	while (a != b) {
		if (a > b)
			a = a - b;
		else
			b = b - a;
	}
	return a;
}
int main() {
	for (int i = 1; i <= 2021; i++)
		for (int j = 1; j <= 2021; j++)
		{
			if (i == j)
				mp[i][j] = MAX;
			else
				if (abs(i - j) <= 21)
					mp[i][j] = i * j / __gcd(i, j);
				else
					mp[i][j] = MAX;
		}
	for(int i = 1;i <= 2021;i++)
		for(int j = 1;j <= 2021;j++)
			for (int k = 1; k <= 2021; k++)
			{
				if (mp[i][j] > mp[i][k] + mp[k][j])
					mp[i][j] = mp[i][k] + mp[k][j];
			}
	cout << mp[1][2021] << endl;
	return 0;
}

蓝桥学院由21 栋教学楼组成,教学楼编号1 到21。
对于两栋教学楼a 和b,当a 和b 互质时,a 和b 之间有一条走廊直接相连,两个方向皆可通行,否则没有直接连接的走廊。
小蓝现在在第一栋教学楼,他想要访问每栋教学楼正好一次,最终回到第一栋教学楼(即走一条哈密尔顿回路),请问他有多少种不同的访问方案?
两个访问方案不同是指存在某个i,小蓝在两个访问方法中访问完教学楼i 后访问了不同的教学楼。
提示:建议使用计算机编程解决问题。

#include <iostream>
#include <cmath>
#include <vector>
using namespace std;
const int maxn = 21;
const int maxs = 1 << maxn;
typedef long long ll;

int N = 21;
ll dp[maxs + 100][maxn + 1];//dp[i][j],i存状态,j存当前点的序号
int g[maxn + 5][maxn + 5];//存图
int __gcd(int a, int b) {
    while (a != b) {
        if (a > b)
            a = a - b;
        else
            b = b - a;
    }
    return a;
}
ll dfs(int state, int pos) {
    //当前状态是state(state存储的是从1到pos(假设已经走了第pos位置)之后所有点的状态)
    //当前状态的路径是从1经若干点走到点pos了,本次要处理的是第pos位置
    if (dp[state][pos] != -1)return dp[state][pos];//一定要用到存储的状态!!!
    ll res = 0;
    for (int i = 1; i < N; i++) {//找本次pos位置的上一个位置状态,状态转换
        if (((state >> i) & 1) == 0)continue;//第i个点没走过--不是上一个状态
        //是上一个状态
        if (g[i][pos] == 1) {//要有边才能转换
            //改变state中存的pos的上一个点i的状态,状态转移--大状态变成小状态
            dp[state - (1 << pos)][i] = dfs(state - (1 << pos), i);
            res += dp[state - (1 << pos)][i];//不要直接用dp[state][pos]加因为初值是-1!!
        }
    }
    return dp[state][pos] = res;
}
int main()
{
    memset(dp, -1, sizeof dp);
    for (int i = 1; i <= N; i++) {
        for (int j = i; j <= N; j++) {
            if (__gcd(i, j) == 1)g[i - 1][j - 1] = 1, g[j - 1][i - 1] = 1;//1到N映射为0到N-1
        }
    }
    //从1走到任何一个点,都是可以的,方案数是1,状态是1<<i
    for (int i = 1; i < N; i++) {//初始化
        dp[(1 << i) + 1][i] = 1;
    }

    ll sum = 0;
    for (int i = 1; i < N; i++) {
        dp[(1 << N) - 1][i] = dfs((1 << N) - 1, i);
        sum += dp[(1 << N) - 1][i];
        cout << dp[(1 << N) - 1][i] << endl;
    }
    cout << endl << sum << endl;
    return 0;
}



//#include<bits/stdc++.h> 
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <algorithm>
#include <queue>
#include <stack>
#include <map>
#include <vector>
#include <cstring>//memset
#include <string>
using namespace std;
const int maxn = 1e8;
bool IsPrime(int m){
	if(m == 2)
		return true;
	int tmp = sqrt(m);
	for(int i = 2;i <= tmp;i++)
		if(m%i == 0)
			return false;
	return true;
}
int gcd_wx(int a,int b){
	while(a!=b)
	{
		if(a>b)
			a = a-b;
		else
			b = b-a;
	}
	return a;
}
bool leapYear(int y){
	if(y%400 == 0)
		return true;
	if(y%4 == 0&& y%100!= 0)
		return true;
	return false;
}
int dx[4] = {0,0,1,-1};
int dy[4] = {1,-1,0,0};

struct Step{
	int x;
	int steps;//第steps步走到位置x
	Step(int xx,int s):x(xx),steps(s){
	}
};
queue<Step>q;
struct node{
	//输出最短路径的步数和路径 
	int x;
	int y;
	int front;//记录上一个节点
	int steps; 
	node():x(-1),y(-1),front(-1),steps(0){
	}
	node(int xx,int yy,int ff,int s):x(xx),y(yy),front(ff),steps(s){
	}
}; 
int mp[2025][2025];//存放迷宫地图  
int visited[2025];//标记 
int path[2025][2025];//存放路径path[i][j]在最短路i-j上,j的直接前驱是path[i][j] 
int dis[2025][2025];
int main(){
	//建图 
	for(int i = 1;i <= 2021;i++)
		for(int j = 1;j <= 2021;j++)
			{
				if(i == j)
					mp[i][j] = maxn;
				else
					if(abs(i-j)<=21)
						mp[i][j] = i*j/gcd_wx(i,j);
					else
						mp[i][j] = maxn;
			} 
	//floyd--带路径
	for(int i = 1;i <= 2021;i++)
		 for(int j = 1;j <= 2021;j++)
		 	{
		 		dis[i][j] = mp[i][j];
		 		path[i][j] = i;
		 	}
	for(int k = 1;k <= 2021;k++)//插点,在i-j之间插点k
		for(int i = 1;i <= 2021;i++)
			for(int j = 1;j <= 2021;j++) 
				{
					if(dis[i][j] > dis[i][k]+dis[k][j])
						{
							dis[i][j] = dis[i][k]+dis[k][j];
							path[i][j] = path[k][j]; 
						}
				}
	cout<<dis[1][2021]<<endl;
	cout<<2021<<" ";
	int ans = 1;int k = 2021;
	while(true){
		if(ans%10 == 0)cout<<endl;
		cout<<path[1][k]<<" ";
		ans++;
		if(path[1][k] == 1)break;
		k = path[1][k];
	}
	cout<<"从1到2021一共有"<<ans<<"个数"<<endl; 
	return 0;
}

枚举三个数,满足一定条件

小蓝有一个超大的仓库,可以摆放很多货物。
现在,小蓝有n 箱货物要摆放在仓库,每箱货物都是规则的正方体。
小蓝规定了长、宽、高三个互相垂直的方向,每箱货物的边都必须严格平行于长、宽、高。
小蓝希望所有的货物最终摆成一个大的立方体。即在长、宽、高的方向上分别堆L、W、H 的货物,满足n = L × W × H。
给定n,请问有多少种堆放货物的方案满足要求。
例如,当n = 4 时,有以下6 种方案:1×1×4、1×2×2、1×4×1、2×1×2、2×2×1、4×1×1。
请问,当n = 2021041820210418 (注意有16 位数字)时,总共有多少种
方案?
提示:建议使用计算机编程解决问题。

#include <iostream>
#include <cmath>
#include <vector>
using namespace std;
const int MAX = 1e9;
const long long n = 2021041820210418;
vector<long long> v;//存储所有因数
int main() {
	for(int i = 1;i<=sqrt(n);i++)
		if (n % i == 0)
		{
			v.push_back(i);
			v.push_back(n / i);
		}
	long long ans = 0;
	int size = v.size();
	for (int i = 0; i < size; i++)
		for (int j = 0; j < size; j++)
			if (n % (v[i] * v[j]) == 0)
				ans++;
	cout << ans;
	return 0;
}

枚举三个数,满足一定条件

问题描述

  众所周知,小葱同学擅长计算,尤其擅长计算一个数是否是另外一个数的倍数。但小葱只擅长两个数的情况,当有很多个数之后就会比较苦恼。现在小葱给了你 n 个数,希望你从这 n 个数中找到三个数,使得这三个数的和是 K 的倍数,且这个和最大。数据保证一定有解。

输入格式

  从标准输入读入数据。

  第一行包括 2 个正整数 n, K。
  第二行 n 个正整数,代表给定的 n 个数。

输出格式

  输出到标准输出。
  输出一行一个整数代表所求的和。

样例入

  4 3
  1 2 3 4

样例输出

9

样例说明

  选择2、3、4。

数据约定

  对于 30% 的数据,n <= 100。
  对于 60% 的数据,n <= 1000。
  对于另外 20% 的数据,K <= 10。
  对于 100% 的数据,1 <= n <= 10^5, 1 <= K <= 10^3,给定的 n 个数均不超过 10^8。


  资源约定:
  峰值内存消耗(含虚拟机) < 256M
  CPU消耗 < 1000ms


  请严格按要求输出,不要画蛇添足地打印类似:“请您输入...” 的多余内容。

  注意:
  main函数需要返回0;
  只使用ANSI C/ANSI C++ 标准;
  不要调用依赖于编译环境或操作系统的特殊函数。
  所有依赖的函数必须明确地在源文件中 #include <xxx>
  不能通过工程设置而省略常用头文件。

  提交程序时,注意选择所期望的语言类型和编译器类型。
 

#include <iostream>
#include<cstdio>
#include <cmath>
#include <cstdlib>
#include <cstring>
#include <vector>
#include <algorithm>
#include <map>
#include <memory.h>
#include <stack>
#include <queue>
#include <string>
#define ll long long
using namespace std;
int n, k;
int group[1010][3];
int ans = 0;
int main() {
	cin >> n >> k;
	int res;
	//直接分组
	for (int i = 0; i < n; i++) {
		int x;
		cin >> x;//接受输入的值
		res = x % k;//数x是属于桶res的
		if (x > group[res][0]) {//x应该是当前桶中最大的数--移动
			group[res][2] = group[res][1];
			group[res][1] = group[res][0];
			group[res][0] = x;
		}
		else {
			if (x > group[res][1]) {//x应该是当前桶中第二大的数--移动
				group[res][2] = group[res][1];
				group[res][1] = x;
			}
			else
				if (x > group[res][2]) {//x应该是当前桶中第三大的数--移动
					group[res][2] = res;
				}
		}	
	}
	//k在1000以内
	//模拟
	//取三个数的过程
	//三层循环---在和最大值的约束下,确定了前两个数,则第三个数唯一确定
	//暴力枚举前两个数即可
	//模拟从k个桶中取三个数的过程
	int v1, v2, v3;
	int z;//记录第三个数所在的桶
	for (int i = 0; i < k; i++) {//枚举第一个数所在的桶
		v1 = group[i][0];
		if (v1 != 0) {
			for (int j = 0; j < k; j++) {//枚举第二个数所在的桶
				if (i == j)
					v2 = group[i][1];
				else
					v2 = group[j][0];
				if (v2 != 0) {
					//第二个数是有效的---前两个数确定后,第三个数是唯一确定的,
					//下面找到在当前两个数的情况下,哪个第三个数使和最大 z的设置,使循环由三重简化为二重
					z = (k - (i + j) % k) % k;
					if (i == j) {//前两个数取自一个桶
						if (z == i)//第三个数在桶i中
							v3 = group[i][2];
						else//第三个数在非i非j桶中
							v3 = group[z][0];
					}
					else//前两个数不是取自同一个桶
					{
						if (z == i)//第三个数在桶i中
							v3 = group[i][1];
						else
							if (z == j)//第三个数在桶j中
								v3 = group[j][1];
							else
								v3 = group[z][0];//第三个数在非i非j桶中
					}
					if (v3 != 0)//第三个数是有效的--三个数成功取出
						ans = max(v1 + v2 + v3, ans);
				}
			}
		}
	}
	cout << ans << endl;
	return 0;
}

枚举三个数,满足一定条件

到x星球旅行的游客都被发给一个整数,作为游客编号。
x星的国王有个怪癖,他只喜欢数字3,5和7。
国王规定,游客的编号如果只含有因子:3,5,7,就可以获得一份奖品。
前10个幸运数字是:3 5 7 9 15 21 25 27 35 45,因而第11个幸运数字是:49
小明领到了一个幸运数字 59084709587505。
去领奖的时候,人家要求他准确说出这是第几个幸运数字,否则领不到奖品。
请你帮小明计算一下,59084709587505是第几个幸运数字。

#include <iostream>
#include<cstdio>
#include <cmath>
#include <cstdlib>
#include <cstring>
#include <vector>
#include <algorithm>
#include <map>
using namespace std;
int gcd(int a, int b) {
	while (a != b) {
		if (a > b)
			a = a - b;
		else
			b = b - a;
	}
	return a;
}
int main()
{
	//long long n = 59084709587505;
	int ans = 0;
	//计算因数2和5的个数
	///*for (long long j = 3; j <= 59084709587505; j++) {
	//	long long n = j;
	//	int count3 = 0, count5 = 0, count7 = 0;
	//	if (n % 3 != 0 && n % 5 != 0 && n % 7 != 0)continue;
	//	while (n % 3 == 0) {
	//		count3++;
	//		n /= 3;
	//	}
	//	while (n % 5 == 0) {
	//		count5++;
	//		n /= 5;
	//	}
	//	while (n % 7 == 0) {
	//		count7++;
	//		n /= 7;
	//	}
	//	if(n == 1)
	//		ans++;
	//}*/
	int i, j, k;
	long long x = 59084709587505;
	for (i = 0; pow(3, i) <= x; i++)
		for (j = 0; pow(5, j) <= x; j++)
			for (k = 0; pow(7, k) <= x; k++)
			{
				if (pow(3, i) * pow(5, j) * pow(7, k) <= x)
				{
					ans++;
				}
			}
	printf("%d", ans - 1);//其中i,j,k都为0时不符合要求,要减去1
	//cout << ans << endl;//1905 1906
	return 0;
}

思维题

如下的10行数据,每行有10个整数,请你求出它们的乘积的末尾有多少个零?

5650 4542 3554 473 946 4114 3871 9073 90 4329 
2758 7949 6113 5659 5245 7432 3051 4434 6704 3594 
9937 1173 6866 3397 4759 7557 3070 2287 1453 9899 
1486 5722 3135 1170 4014 5510 5120 729 2880 9019 
2049 698 4582 4346 4427 646 9742 7340 1230 7683 
5693 7015 6887 7381 4172 4341 2909 2027 7355 5649 
6701 6645 1671 5978 2704 9926 295 3125 3878 6785 
2066 4247 4800 1578 6652 4616 1113 6205 3264 2915 
3966 5291 2904 1285 2193 1428 2265 8730 9436 7074 
689 5510 8243 6114 337 4096 8199 7313 3685 211 

一开始,用高精度计算,暴力求解

代码如下

//#include<bit/stdc++.h> 
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <algorithm>
#include <queue>
#include <stack>
#include <map>
#include <vector>
#include <cstring>//memset
#include <string>
using namespace std;
const int maxn = 1e5 + 100;
bool IsPrime(int m) {
	if (m == 2)
		return true;
	int tmp = sqrt(m);
	for (int i = 2; i <= tmp; i++)
		if (m % i == 0)
			return false;
	return true;
}
int gcd_wx(int a, int b) {
	while (a != b)
	{
		if (a > b)
			a = a - b;
		else
			b = b - a;
	}
	return a;
}
bool leapYear(int y) {
	if (y % 400 == 0)
		return true;
	if (y % 4 == 0 && y % 100 != 0)
		return true;
	return false;
}
int qushu(int m){
	while(m){
		int tmp = m%10;
		m/=10;
	}
	return 0;
}
int dx[4] = { 1,0,0,-1 };
int dy[4] = { 0,-1,1,0 };
char dire[4] = { 'D','L','R','U' };
struct Road{
	int d;
	int cost;
	Road ():d(0),cost(0){
	}
	Road(int dd,int c):d(dd),cost(c){
	}
};
bool cmp(int a,int b){
	return a>b;
}

int a[200];
int c[100000];
int b1[100000], b2[100000];
int tmp[10000];
int transfer(int number,int b2[]) {
	int i = 1;
	while (number) {
		b2[i++] = number % 10;
		number /= 10;
	}
	return i;
}
int mult(int la, int lb,int b1[],int b2[]) {
	int lc = la + lb;
	for(int i = 1;i <=la;i++)
		for (int j = 1; j <= lb; j++)
		{
			c[i + j - 1] += b1[i] * b2[j];
			c[i + j] += c[i + j - 1] / 10;
			c[i + j - 1] %= 10;
		}
	if (c[lc] == 0 && lc > 0)lc--;
	return lc;
}
int main()
{
	int ans = 0;
	long long sum = 1;
	for(int i = 1;i <= 100;i++) {
		cin>>a[i];
	}
	int la = transfer(a[1], b1);//第一个数转化成数组
	int lb = transfer(a[2], b2);//第二个数转化成数组
	int k = 3;//第三个数下标
	int lcNow = mult(la, lb, b1, b2);//前两个数相乘结果的数的个数
	while (k <= 100) {
		for (int i = 1; i <= lcNow; i++)
			b1[i] = c[i];//临时中转
		lb = transfer(a[k], b2);//第k个数转化成数组
		lcNow = mult(lcNow, lb, b1, b2);//lcNow--b1,lb--b2
		k++;
	}
	for (int i = 1; i <= lcNow; i++)
		if (c[i] == 0)ans++;
		else
			break;
	cout<<ans<<endl;
	return 0;
}

10的因数是1,2,5,10,只要有成对的因数2-5,就会有10,代码如下

#include <iostream>
#include<cstdio>
#include <cmath>
#include <cstdlib>
#include <cstring>
#include <vector>
#include <algorithm>
#include <map>
using namespace std;
int gcd(int a, int b) {
	while (a != b) {
		if (a > b)
			a = a - b;
		else
			b = b - a;
	}
	return a;
}
int main()
{
	int count2 = 0, count5 = 0;
	int ans;
	int n;
	//计算因数2和5的个数
	for (int i = 1; i <= 100; i++) {
		cin >> n;
		while (n % 2 == 0) {
			count2++;
			n /= 2;
		}
		while (n % 5 == 0) {
			count5++;
			n /= 5;
		}
	}
	ans = min(count2, count5);
	cout << ans << endl;
	return 0;
}

答案是31

四平方和

四平方和定理,又称为拉格朗日定理:
  每个正整数都可以表示为至多4个正整数的平方和。
  如果把0包括进去,就正好可以表示为4个数的平方和。

  比如:
  5 = 0^2 + 0^2 + 1^2 + 2^2
  7 = 1^2 + 1^2 + 1^2 + 2^2
  (^符号表示乘方的意思)

  对于一个给定的正整数,可能存在多种平方和的表示法。
  要求你对4个数排序:
  0 <= a <= b <= c <= d
  并对所有的可能表示法按 a,b,c,d 为联合主键升序排列,最后输出第一个表示法


  程序输入为一个正整数N (N<5000000)
  要求输出4个非负整数,按从小到大排序,中间用空格分开

  例如,输入:
  5
  则程序应该输出:
  0 0 1 2

  再例如,输入:
  12
  则程序应该输出:
  0 2 2 2

  再例如,输入:
  773535
  则程序应该输出:
  1 1 267 838

  资源约定:
  峰值内存消耗 < 256M
  CPU消耗 < 3000ms

  请严格按要求输出,不要画蛇添足地打印类似:“请您输入...” 的多余内容。

  所有代码放在同一个源文件中,调试通过后,拷贝提交该源码。

  注意: main函数需要返回0
  注意: 只使用ANSI C/ANSI C++ 标准,不要调用依赖于编译环境或操作系统的特殊函数。
  注意: 所有依赖的函数必须明确地在源文件中 #include <xxx>, 不能通过工程设置而省略常用头文件。

  提交时,注意选择所期望的编译器类型。

暴力题,枚举三个数即可,第四个数不要枚举

#include<iostream>
#include<cstdio>
#include<cstring>
#include <cmath>
using namespace std;
int a[10];
int main(){
	int n;
	while(scanf("%d",&n)!=EOF){
		int q = sqrt(n);
		int flag = 0;
		for(int i = 0;i <= q;i++)
		{
			for(int j = i;j <= q;j++)
			{
				for(int k = j;k <= q;k++)
		            {
		            	int tmp = n - i*i-j*j-k*k;
		            	int sqrtmp = sqrt(tmp);
		            	if(sqrtmp*sqrtmp == tmp)
		            	    {
		            	    	flag = 1;
		            	    	cout<<i<<" "<<j<<" "<<k<<" "<<sqrtmp<<endl;
		            	    	break;
		            	    }
		            }
		        if(flag)
		            break;
			}
		        
		    if(flag)
		        break;
		}
		    
	}
	return 0;
} 

dfs剪枝--恢复现场

//#include<bits/stdc++.h> 
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <algorithm>
#include <queue>
#include <stack>
#include <map>
#include <vector>
#include <cstring>//memset
#include <string>
using namespace std;
//const int maxn = 1e8;
bool IsPrime(int m){
	if(m == 2)
		return true;
	int tmp = sqrt(m);
	for(int i = 2;i <= tmp;i++)
		if(m%i == 0)
			return false;
	return true;
}
int gcd_wx(int a,int b){
	while(a!=b)
	{
		if(a>b)
			a = a-b;
		else
			b = b-a;
	}
	return a;
}
bool leapYear(int y){
	if(y%400 == 0)
		return true;
	if(y%4 == 0&& y%100!= 0)
		return true;
	return false;
}
int dx[4] = {0,0,1,-1};
int dy[4] = {1,-1,0,0};

struct Step{
	int x;
	int steps;//第steps步走到位置x
	Step(int xx,int s):x(xx),steps(s){
	}
};
queue<Step>q;
struct node{
	//输出最短路径的步数和路径 
	int x;
	int y;
	int front;//记录上一个节点
	int steps; 
	node():x(-1),y(-1),front(-1),steps(0){
	}
	node(int xx,int yy,int ff,int s):x(xx),y(yy),front(ff),steps(s){
	}
}; 
int K,N,R;
struct Road{
	int d,L,t;
}; 
vector<vector<Road> > G(110);//G[i] 与节点i相连的所有边
int minLen;//记录最短路径 
int nowLen;//记录当前路径
int nowCost;
int visited[110];
int costMinLen[10010][110];//costMinLen[i][j]花i元走到j处,对应的最短路径长度 
void dfs(int s){
	//从s出发,进行深搜
	if(s == N)
		{
			minLen = min(minLen,nowLen);
			return ;
		}
	//if(visited[s])return;//在主函数中标记了起点,这里不能再有这句话 
	//visited[s] = 1;
	int size = G[s].size();
	for(int i = 0;i < size;i++)
		{
			Road r = G[s][i];
			if(visited[r.d])continue;
			if(nowCost+r.t>K)continue;
			if(nowLen+r.L >= minLen)continue;//
			if(nowLen+r.L >= costMinLen[nowCost+r.t][r.d]) continue;//
			costMinLen[nowCost][r.d] = nowLen+r.L;//剪枝中的记忆化 
			visited[r.d] = 1;//标记 
			nowCost+=r.t;//花费 
			nowLen+=r.L;//路径长度 
			dfs(r.d);//深搜 
			//恢复现场 
			visited[r.d] = 0;
			nowCost-=r.t;
			nowLen-=r.L;
		} 
} 
 
int main(){
	cin>>K>>N>>R;
	for(int i = 0;i < R;i++)
		{
			int s;
			Road r;
			cin>>s>>r.d>>r.L>>r.t;
			if(s!=r.d)
				G[s].push_back(r);
		}
	memset(visited,0,sizeof(visited));
	for(int i = 0;i < 10010;i++)
		for(int j = 0;j < 110;j++)
			costMinLen[i][j] = 1<<30;
	nowLen = 0;
	minLen = 1<<30;
	nowCost = 0;
	visited[1] = 1;
	dfs(1);
	if(minLen<(1<<30))
		cout<<minLen<<endl;
	else
		cout<<-1<<endl;
	return 0;
}

盾神与困难数独

问题描述

  有一天,盾神接触到了风靡世界的小游戏——数独!!!盾神非常感兴趣,不惜翘课用了一天的时间把数独玩得出神入化!!!于是他要过来考考你。经过“盾神与简单数独”的磨练后,你会做9*9的了。

输入格式

  输入为9*9的矩阵,如果第i行第j列为0,则该格子未填数;否则该格子已经有数。

输出格式

  输出为1个9*9的矩阵,表示字典序最小的方案。如无解则输出NO。
  矩阵大小关系的定义:第一关键字为a[1][1],第二关键字为a[1][2],……第四关键字为a[1][4],第五关键字为a[2][1],以此类推。矩阵A小于矩阵B,当且仅当存在k,A和B的前k-1个关键字的值都相等,而A的第k个关键字的值小于B的第k个关键字的值。矩阵A等于矩阵B,当且仅当A小于B和B小于A都不成立。
  字典序升序的定义:在矩阵序列a中,对于任意的i<=j,有a[i]<=a[j]。

样例输入

1 2 3 4 5 6 7 8 9
2 0 0 0 0 0 0 0 0
3 0 0 0 0 0 0 0 0
4 0 0 0 0 0 0 0 0
5 0 0 0 0 0 0 0 0
6 0 0 0 0 0 0 0 0
7 0 0 0 0 0 0 0 0
8 0 0 0 0 0 0 0 0
9 0 0 0 0 0 0 0 0

样例输出

NO

样例输入

1 2 3 4 5 6 7 8 9
0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0

样例输出

1 2 3 4 5 6 7 8 9
4 5 6 7 8 9 1 2 3
7 8 9 1 2 3 4 5 6
2 1 4 3 6 5 8 9 7
3 6 5 8 9 7 2 1 4
8 9 7 2 1 4 3 6 5
5 3 1 6 4 2 9 7 8
6 4 2 9 7 8 5 3 1
9 7 8 5 3 1 6 4 2

数据规模和约定

  矩阵中所有数的值为0到9。

补充一个常识:数独定义

数独(shù dú)是源自18世纪瑞士的一种数学游戏。是一种运用纸、笔进行演算的逻辑游戏。玩家需要根据9×9盘面上的已知数字,推理出所有剩余空格的数字,并满足每一行、每一列、每一个粗线宫(3*3)内的数字均含1-9,不重复  。

数独盘面是个九宫,每一宫又分为九个小格。在这八十一格中给出一定的已知数字和解题条件,利用逻辑和推理,在其他的空格上填入1-9的数字。使1-9每个数字在每一行、每一列和每一宫中都只出现一次,所以又称“九宫格”。

大致思路

每个3*3的粗线宫都含数字1-9,dfs,判断每行每列是否也满足1-9

上面的思路是错误的,不需要对每一个3*3的粗线格进行dfs,只要把3*3的粗线格的看作和行列一样的地位即可,就是判重

代码如下

//#include<bit/stdc++.h> 
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <algorithm>
#include <queue>
#include <stack>
#include <map>
#include <vector>
#include <cstring>//memset
#include <string>
using namespace std;
//const int maxn = 1e8;
bool IsPrime(int m) {
	if (m == 2)
		return true;
	int tmp = sqrt(m);
	for (int i = 2; i <= tmp; i++)
		if (m % i == 0)
			return false;
	return true;
}
int gcd_wx(int a, int b) {
	while (a != b)
	{
		if (a > b)
			a = a - b;
		else
			b = b - a;
	}
	return a;
}
bool leapYear(int y) {
	if (y % 400 == 0)
		return true;
	if (y % 4 == 0 && y % 100 != 0)
		return true;
	return false;
}
int dx[4] = { 1,0,0,-1 };
int dy[4] = { 0,-1,1,0 };
char dire[4] = { 'D','L','R','U' };
struct Step {
	int x;
	int steps;//第steps步走到位置x
	Step(int xx, int s) :x(xx), steps(s) {
	}
};
//queue<Step>q;
struct node {
	//输出最短路径的步数和路径 
	int x;
	int y;
	int front;//记录上一个节点
	int steps;
	char dir;
	node() :x(-1), y(-1), front(-1), steps(0), dir('w') {
	}
	node(int xx, int yy, int ff, int s, char d) :x(xx), y(yy), front(ff), steps(s), dir(d) {
	}
};
struct dish {
	string s;
	int steps;
	int front;
	int dir;
	dish() :s("aaaaaaaaaa"), steps(-1), front(-91), dir(-1) {
	}//定义这个用于vector<dish> dque(1000000) 
	dish(string ss, int s, int ff, int d) :s(ss), steps(s), front(ff), dir(d) {
	}//定义这个用于赋值构造 
};

struct fat {
	int x;
	int y;
	int steps;
	fat() :x(-1), y(-1), steps(-1) {
	}
	fat(int xx, int yy, int s) :x(xx), y(yy), steps(s) {
	}
};

int mp[10][10];//存储地图
//理解标记数组定义 
bool colFlag[10][10];//列标记,colFlag[i][j]=1表示第i列中已经有j这个数了
bool rowFlag[10][10];//行标记,rowFlag[i][j] = 1表示第i行中已经有j这个数了
bool flag33[10][10];//3_by_3方阵的标记,flag33[i][j] = 1表示第i个3*3的方阵中有j这个数了,方阵一共有9个,编号从左至右,从上到下依次是0-1-2...-8
int dfs(int num){
	//在进行dfs之前,我们对于已经出现的数进行了三种标记-行标记列标记和group33标记 
	//从第num个数开始,排到最后一个数,得到的方阵符合数独则返回1,否则返回0
	if(num == 81){
		for(int i = 0;i < 9;i++){
			for(int j = 0;j <9;j++)
				cout<<mp[i][j]<<" ";
			cout<<endl;
		}
		return 1;		
	} 
	else{
		//怎么获得下面这三个数 
		//获得第num个数所在的行号、列号、和小方阵号 
		int row = num/9;
		int col = num%9;
		int groupIndex = (row/3)*3+col/3;
		
		if(mp[row][col] == 0){//还没有填数 
			for(int i = 1;i <= 9;i++){//填1-9 ,按照从1到9进行遍历,可以获得字典序最小 
				if(colFlag[row][i]||rowFlag[col][i]||flag33[groupIndex][i])continue;//重复了直接跳过
				//打标记 
				mp[row][col] = i;
				colFlag[row][i] = 1;
				rowFlag[col][i] = 1;
				flag33[groupIndex][i] = 1;
				//下一次搜索 
				if(dfs(num+1))
					return 1;//这和以前不一样?原因:这是在找路,找第一条路 ,找到了就立刻返回 
				//去标记-恢复现场 
				mp[row][col] = 0;
				colFlag[row][i] = 0;
				rowFlag[col][i] = 0;
				flag33[groupIndex][i] = 0;
			}
		}
		else{
			if(dfs(num+1))
				return 1;
		}
		return 0;	
	}
} 

int main() {
	//接受输入数据 
	for(int i = 0;i < 9;i++)
		for(int j = 0;j < 9;j++)
			{
				cin>>mp[i][j];
				int groupIndex = (i/3)*3+j/3;
				if(mp[i][j]) {
					if(colFlag[i][mp[i][j]]||rowFlag[j][mp[i][j]]||flag33[groupIndex][mp[i][j]]){
					cout<<"NO"; 
					return 0;
				}
				colFlag[i][mp[i][j]] = 1;
				rowFlag[j][mp[i][j]] = 1;
				flag33[groupIndex][mp[i][j]] = 1;
				}
			}
	int ans = dfs(0);
	if(ans == 0)cout<<"NO"; 
	return 0;
}

分析上面的代码,这实际上是利用dfs来找一条路径----之前都是利用bfs进行最小字典序路径的搜索。根据上面的代码,可以看出,利用dfs进行字典序最小情况搜索时,具体操作如下, 此时,dfs时,我们设置返回值来表示当前是否找到了路径,找到了即返回,

//下一次搜索 
				if(dfs(num+1))
					return 1;//这和以前不一样?
                    //原因:这是在找路,找第一条路 ,找到了就立刻返回 
				

 一般情况下,这里的话是dfs(num+1));在这里,这里找到了一条路就返回,不进行深搜,停止。

此外,这里,由num转化为row和col和groupIndex,这是较为常规的,这个思路可以借鉴二维数组转化为一维数组,int a[3][4],那么a[i][j]就是数组a中的第4*(i-1)+j -1个数。 同理,对于数组中第m个数,对应a[m/4][m%4]。

下面再给一例:

剪邮票

如下图, 有12张连在一起的12生肖的邮票。现在你要从中剪下5张来,要求必须是连着的。(仅仅连接一个角不算相连)


比如,下面两张图中,粉红色所示部分就是合格的剪取。

请你计算,一共有多少种不同的剪取方法。 

分析:这道题中,我们每次从12个数中找5个数,利用二进制状态压缩(1表示选了,0表示没选),不过,需要将这个状态转化为这个数组里的数是否被选到了。 

下面的代码是错误的

//#include<bit/stdc++.h> 
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <algorithm>
#include <queue>
#include <stack>
#include <map>
#include <vector>
#include <cstring>//memset
#include <string>
using namespace std;
//const int maxn = 1e8;
bool IsPrime(int m) {
	if (m == 2)
		return true;
	int tmp = sqrt(m);
	for (int i = 2; i <= tmp; i++)
		if (m % i == 0)
			return false;
	return true;
}
int gcd_wx(int a, int b) {
	while (a != b)
	{
		if (a > b)
			a = a - b;
		else
			b = b - a;
	}
	return a;
}
bool leapYear(int y) {
	if (y % 400 == 0)
		return true;
	if (y % 4 == 0 && y % 100 != 0)
		return true;
	return false;
}
int dx[4] = { 1,0,0,-1 };
int dy[4] = { 0,-1,1,0 };
char dire[4] = { 'D','L','R','U' };
struct Step {
	int x;
	int steps;//第steps步走到位置x
	Step(int xx, int s) :x(xx), steps(s) {
	}
};
//queue<Step>q;
struct node {
	//输出最短路径的步数和路径 
	int x;
	int y;
	int front;//记录上一个节点
	int steps;
	char dir;
	node() :x(-1), y(-1), front(-1), steps(0), dir('w') {
	}
	node(int xx, int yy, int ff, int s, char d) :x(xx), y(yy), front(ff), steps(s), dir(d) {
	}
};
struct dish {
	string s;
	int steps;
	int front;
	int dir;
	dish() :s("aaaaaaaaaa"), steps(-1), front(-91), dir(-1) {
	}//定义这个用于vector<dish> dque(1000000) 
	dish(string ss, int s, int ff, int d) :s(ss), steps(s), front(ff), dir(d) {
	}//定义这个用于赋值构造 
};

struct fat {
	int x;
	int y;
	int steps;
	fat() :x(-1), y(-1), steps(-1) {
	}
	fat(int xx, int yy, int s) :x(xx), y(yy), steps(s) {
	}
};

int mp[10][10];
bool visited[10][10];
int getiBit(int n,int i) {
	return (n>>i)&1;
}
bool checkFirst(int state){
	int count = 0;
	for(int i = 0;i < 12;i++)
		if(getiBit(state,i))
			count++;
	return count==5;
}
void dfs(int x,int y){
	if(visited[x][y]||!mp[x][y])return;
	visited[x][y] = true;//标记 
	for(int i = 0;i < 4;i++){
		int ax = x+dx[i];
		int ay = y+dy[i];
		if(ax<0&&ax>3&&ay<0&&ay>2&&!visited[ax][ay]&&mp[ax][ay])
			dfs(ax,ay);
	}
	return;	
}
int main() {
	int res = 0;
	for(int i = 1;i <(1<<12);i++)
		if(checkFirst(i)){
			memset(visited,0,sizeof(visited));
			for(int j = 0;j < 12;j++)
				mp[j/4][j%4] = getiBit(i,j);
			int flag = 0;
			for(int i1 = 0;i1 < 4;i1++){
				for(int j1 = 0;j1 < 3;j1++)
					{
						if(mp[i1][j1]){
							dfs(i1,j1);
							flag = 1;
							break;
						}
					}
					if(flag == 1){
						int ans = 0;
						for(int i2 = 0;i2 < 4;i2++)
							for(int j2 = 0;j2 < 3;j2++)
							{
								if(visited[i2][j2])ans++;
							}
						if(ans==5) res++;
						break;
					}
			}
		}
	cout<<res<<endl;
	return 0;
}

正确的代码如下,结果是116

//#include<bit/stdc++.h> 
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <algorithm>
#include <queue>
#include <stack>
#include <map>
#include <vector>
#include <cstring>//memset
#include <string>
using namespace std;
//const int maxn = 1e8;
bool IsPrime(int m) {
	if (m == 2)
		return true;
	int tmp = sqrt(m);
	for (int i = 2; i <= tmp; i++)
		if (m % i == 0)
			return false;
	return true;
}
int gcd_wx(int a, int b) {
	while (a != b)
	{
		if (a > b)
			a = a - b;
		else
			b = b - a;
	}
	return a;
}
bool leapYear(int y) {
	if (y % 400 == 0)
		return true;
	if (y % 4 == 0 && y % 100 != 0)
		return true;
	return false;
}
int dx[4] = { 1,0,0,-1 };
int dy[4] = { 0,-1,1,0 };
char dire[4] = { 'D','L','R','U' };
struct Step {
	int x;
	int steps;//第steps步走到位置x
	Step(int xx, int s) :x(xx), steps(s) {
	}
};
//queue<Step>q;
struct node {
	//输出最短路径的步数和路径 
	int x;
	int y;
	int front;//记录上一个节点
	int steps;
	char dir;
	node() :x(-1), y(-1), front(-1), steps(0), dir('w') {
	}
	node(int xx, int yy, int ff, int s, char d) :x(xx), y(yy), front(ff), steps(s), dir(d) {
	}
};
struct dish {
	string s;
	int steps;
	int front;
	int dir;
	dish() :s("aaaaaaaaaa"), steps(-1), front(-91), dir(-1) {
	}//定义这个用于vector<dish> dque(1000000) 
	dish(string ss, int s, int ff, int d) :s(ss), steps(s), front(ff), dir(d) {
	}//定义这个用于赋值构造 
};

struct fat {
	int x;
	int y;
	int steps;
	fat() :x(-1), y(-1), steps(-1) {
	}
	fat(int xx, int yy, int s) :x(xx), y(yy), steps(s) {
	}
};

int mp[10][10];
int visited[10][10];
int getiBit(int n, int i) {
	return (n >> i) & 1;
}
bool checkFirst(int state) {
	int count = 0;
	for (int i = 0; i < 12; i++)
		if (getiBit(state, i))
			count++;
	return count == 5;
}
void dfs(int x, int y) {
	if (visited[x][y])return;
	visited[x][y] = 1;//标记 
	for (int i = 0; i < 4; i++) {
		int ax = x + dx[i];
		int ay = y + dy[i];
		if (ax >= 0 && ax<=2 && ay >= 0 && ay<=3 && !visited[ax][ay] && mp[ax][ay])
			dfs(ax, ay);
	}
	return;
}
int main() {
	int res = 0;
	for (int i = 1; i < (1 << 12); i++)
		if (checkFirst(i)) {
			memset(visited, 0, sizeof(visited));
			for (int j = 0; j < 12; j++)
				mp[j / 4][j % 4] = getiBit(i, j);
			for (int i2 = 0; i2 < 3; i2++) {
				for (int j2 = 0; j2 < 4; j2++)
				{
					cout << mp[i2][j2] << " ";
				}
				cout << endl;
			}
			int flag = 0;
			for (int i1 = 0; i1 < 3; i1++) {
				for (int j1 = 0; j1 < 4; j1++)
				{
					if (mp[i1][j1]) {
						dfs(i1, j1);
						flag = 1;
						break;
					}
				}
				if (flag == 1) {
					int ans = 0;
					for (int i2 = 0; i2 < 3; i2++)
					{
						for (int j2 = 0; j2 < 4; j2++)
						{
							cout << visited[i2][j2] << " ";
							if (visited[i2][j2])ans++;
						}
						cout << endl;
					}
					if (ans == 5) res++;
					break;
				}
			}
		}
	cout << res << endl;
	return 0;
}

正确代码或者如下

//#include<bit/stdc++.h> 
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <algorithm>
#include <queue>
#include <stack>
#include <map>
#include <vector>
#include <cstring>//memset
#include <string>
using namespace std;
//const int maxn = 1e8;
bool IsPrime(int m) {
	if (m == 2)
		return true;
	int tmp = sqrt(m);
	for (int i = 2; i <= tmp; i++)
		if (m % i == 0)
			return false;
	return true;
}
int gcd_wx(int a, int b) {
	while (a != b)
	{
		if (a > b)
			a = a - b;
		else
			b = b - a;
	}
	return a;
}
bool leapYear(int y) {
	if (y % 400 == 0)
		return true;
	if (y % 4 == 0 && y % 100 != 0)
		return true;
	return false;
}
int dx[4] = { 1,0,0,-1 };
int dy[4] = { 0,-1,1,0 };
char dire[4] = { 'D','L','R','U' };
struct Step {
	int x;
	int steps;//第steps步走到位置x
	Step(int xx, int s) :x(xx), steps(s) {
	}
};
//queue<Step>q;
struct node {
	//输出最短路径的步数和路径 
	int x;
	int y;
	int front;//记录上一个节点
	int steps;
	char dir;
	node() :x(-1), y(-1), front(-1), steps(0), dir('w') {
	}
	node(int xx, int yy, int ff, int s, char d) :x(xx), y(yy), front(ff), steps(s), dir(d) {
	}
};
struct dish {
	string s;
	int steps;
	int front;
	int dir;
	dish() :s("aaaaaaaaaa"), steps(-1), front(-91), dir(-1) {
	}//定义这个用于vector<dish> dque(1000000) 
	dish(string ss, int s, int ff, int d) :s(ss), steps(s), front(ff), dir(d) {
	}//定义这个用于赋值构造 
};

struct fat {
	int x;
	int y;
	int steps;
	fat() :x(-1), y(-1), steps(-1) {
	}
	fat(int xx, int yy, int s) :x(xx), y(yy), steps(s) {
	}
};

int mp[10][10];
bool visited[10][10];
int getiBit(int n,int i) {
	return (n>>i)&1;
}
bool checkFirst(int state){
	int count = 0;
	for(int i = 0;i < 12;i++)
		if(getiBit(state,i))
			count++;
	return count==5;
}
void dfs(int x,int y){
	if(visited[x][y]||!mp[x][y])return;
	visited[x][y] = true;//标记 
	for(int i = 0;i < 4;i++){
		int ax = x+dx[i];
		int ay = y+dy[i];
		if(ax<0&&ax>3&&ay<0&&ay>2&&!visited[ax][ay]&&mp[ax][ay])continue;
			dfs(ax,ay);
	}
	return;	
}
int main() {
	int res = 0;
	for(int i = 1;i <(1<<12);i++)
		if(checkFirst(i)){
			memset(visited,0,sizeof(visited));
			for(int j = 0;j < 12;j++)
				mp[j/4][j%4] = getiBit(i,j);
			int flag = 0;
			for(int i1 = 0;i1 < 3;i1++){
				for(int j1 = 0;j1 < 4;j1++)
					{
						if(mp[i1][j1]){
							dfs(i1,j1);
							flag = 1;
							break;
						}
					}
					if(flag == 1){
						int ans = 0;
						for(int i2 = 0;i2 < 3;i2++)
							for(int j2 = 0;j2 < 4;j2++)
							{
								if(visited[i2][j2])ans++;
							}
						if(ans==5) res++;
						break;
					}
			}
		}
	cout<<res<<endl;
	return 0;
}

D. 大胖子走迷宫

【问题描述】

    小明是个大胖子,或者说是个大大胖子,如果说正常人占用 1 × 1 的面积,小明要占用 5 × 5 的面积。

    由于小明太胖了,所以他行动起来很不方便。当玩一些游戏时,小明相比小伙伴就吃亏很多。

    小明的朋友们制定了一个计划,帮助小明减肥。计划的主要内容是带小明玩一些游戏,让小明在游戏中运动消耗脂肪。走迷宫是计划中的重要环节。

    朋友们设计了一个迷宫,迷宫可以看成是一个由 n x n 个方降组成的方阵,正常人每次占用方阵中 1 × 1 的区域,而小明要占用 5 × 5 的区域。小明的位置定义为小明最正中的一个方格。迷宫四周都有障碍物。

    为了方便小明,朋友们把迷宫的起点设置在了第 3 行第 3 列,终点设置在了第 n - 2 行第 n - 2 列。

    小明在时刻 0 出发,每单位时间可以向当前位置的上、下、左、右移动单位 1 的距离,也可以停留在原地不动。小明走迷宫走得很辛苦,如果他在迷宫里面待的时间很长,则由于消耗了很多脂肪,他会在时刻 k 变成一个胖子,只占用 3 × 3 的区域。如果待的时间更长,他会在时刻 2k 变成一个正常人,只占用 1 × 1 的区域。注意,当小明变瘦时迷宫的起点和终点不变。

    请问,小明最少多长时间能走到迷宫的终点。注意,小明走到终点时可能变瘦了也可能没有变瘦。


【输入形式】

    输入的第一行包含两个整数 n,k。

    接下来 n 行,每行一个由 n 个字符组成的字符串,字符为 + 表示为空地,字符为 * 表示为阻碍物。


【输出形式】

    输出一个整数,表示答案。


【样例输入】

9 5
+++++++++
+++++++++
+++++++++
+++++++++
+++++++++
***+*****
+++++++++
+++++++++
+++++++++


【样例输出】

16


【评分标准】

    对于 30% 的评测用例,1 ≤ n ≤ 50。

    对于 60% 的评测用例,1 ≤ n ≤ 100。

    对于所有评测用例,1 ≤ n ≤ 300,1 ≤ k ≤ 1000。

90/100代码

//#include<bits/stdc++.h> 
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <algorithm>
#include <queue>
#include <stack>
#include <map>
#include <vector>
#include <cstring>//memset
#include <string>
using namespace std;
//const int maxn = 1e8;
bool IsPrime(int m) {
	if (m == 2)
		return true;
	int tmp = sqrt(m);
	for (int i = 2; i <= tmp; i++)
		if (m % i == 0)
			return false;
	return true;
}
int gcd_wx(int a, int b) {
	while (a != b)
	{
		if (a > b)
			a = a - b;
		else
			b = b - a;
	}
	return a;
}
bool leapYear(int y) {
	if (y % 400 == 0)
		return true;
	if (y % 4 == 0 && y % 100 != 0)
		return true;
	return false;
}
int dx[4] = { 1,0,0,-1 };
int dy[4] = { 0,-1,1,0 };
char dire[4] = { 'D','L','R','U' };
struct Step {
	int x;
	int steps;//第steps步走到位置x
	Step(int xx, int s) :x(xx), steps(s) {
	}
};
//queue<Step>q;
struct node {
	//输出最短路径的步数和路径 
	int x;
	int y;
	int front;//记录上一个节点
	int steps;
	char dir;
	node() :x(-1), y(-1), front(-1), steps(0), dir('w') {
	}
	node(int xx, int yy, int ff, int s, char d) :x(xx), y(yy), front(ff), steps(s), dir(d) {
	}
};
struct dish {
	string s;
	int steps;
	int front;
	int dir;
	dish() :s("aaaaaaaaaa"), steps(-1), front(-91), dir(-1) {
	}//定义这个用于vector<dish> dque(1000000) 
	dish(string ss, int s, int ff, int d) :s(ss), steps(s), front(ff), dir(d) {
	}//定义这个用于赋值构造 
};

const int maxn = 350;
char mp[maxn][maxn];
int visited[maxn][maxn];
struct fat {
	int x;
	int y;
	int steps;
	fat() :x(-1), y(-1), steps(-1) {
	}
	fat(int xx, int yy, int s) :x(xx), y(yy), steps(s) {
	}
};
int n, k;
vector<fat> mque(maxn* maxn*100);//开大点,是maxn*maxn时只有50/100
bool check(int x, int y, int r) {//点(x,y)合法返回true,否则返回false 
	if (x + r > n || x - r<1 || y + r>n || y - r < 1)return false;
	for (int i = x - r; i <= x + r; i++)
		for (int j = y - r; j <= y + r; j++)
			if (mp[i][j] == '*')return false;
	return true;
}
int main() {
	cin >> n >> k;

	for (int i = 1; i <= n; i++)
	{
		string tmpString;
		cin >> tmpString;
		for (int j = 1; j <= n; j++)
			mp[i][j] = tmpString[j - 1];
	}
	mque[0] = fat(3, 3, 0);
	visited[3][3] = 1;
	int head = 0, tail = 1;
	while (head <= tail) {
		fat s = mque[head];
		if (s.x == n - 2 && s.y == n - 2) {
			cout << s.steps << endl;
			return 0;
		}
		else
		{
			int rr;
			if (s.steps < k)rr = 2;
			if (s.steps >= k && s.steps < k * 2) rr = 1;
			if (s.steps >= 2 * k)rr = 0;
			for (int i = 0; i < 4; i++) {
				int ax = s.x + dx[i];
				int ay = s.y + dy[i];
				if (check(ax, ay, rr) && !visited[ax][ay]) {
					mque[tail++] = fat(ax, ay, s.steps + 1);
					visited[ax][ay] = 1;
				}
			}
			//怎么写走不了的情况 -模拟走的所有可能-走不了的反面是有一条路可以走 
			int flag = 1;//默认走不了--flag是1表示走不了 
			for (int i = 0; i < 4; i++) {
				int ax = s.x + dx[i];
				int ay = s.y + dy[i];
				if (check(ax, ay, rr)&&!visited[ax][ay]) {
					flag = 0;
					break;
				}
			}
			if (flag) {//走不了,等待 
				mque[tail++] = fat(s.x, s.y, s.steps + 1);
			}
		}
		head++;
	}

	return 0;
}

经检验,mque数组大小开到maxn*maxn*150即可100/100

思考:

模拟+bfs板子

胖子走迷宫,模拟时想象一个方格在移动,方格是5*5或者3*3或者1*1,不要以为是一个5*1或者3*1的矩形在移动;

每一步,能走则尽量走,实在走不了的话,就等---这是核心思路,有点贪心的味道

译成代码,能走,就是说,下一步合法,下一步合法就是说,下一步的坐标满足方格在迷宫中(不出界),方格内部没有障碍物(有障碍物胖子怎么走进去),同时,下一步必须要之前没有走过(走过再走就不合适了)

走和走不了是两种情况,上面的代码可以优化,但是,鉴于这两种情况混在一起用flag进行转换有时会出错,我上面的代码没有用flag联系,

            int rr;
			if (s.steps < k)rr = 2;
			if (s.steps >= k && s.steps < k * 2) rr = 1;
			if (s.steps >= 2 * k)rr = 0;
			for (int i = 0; i < 4; i++) {
				int ax = s.x + dx[i];
				int ay = s.y + dy[i];
				if (check(ax, ay, rr) && !visited[ax][ay]) {
					mque[tail++] = fat(ax, ay, s.steps + 1);
					visited[ax][ay] = 1;
				}
			}
			//怎么写走不了的情况 -模拟走的所有可能-走不了的反面是有一条路可以走 
			int flag = 1;//默认走不了--flag是1表示走不了 
			for (int i = 0; i < 4; i++) {
				int ax = s.x + dx[i];
				int ay = s.y + dy[i];
				if (check(ax, ay, rr)&&!visited[ax][ay]) {
					flag = 0;
					break;
				}
			}
			if (flag) {//走不了,等待 
				mque[tail++] = fat(s.x, s.y, s.steps + 1);
			}

上面这段代码可以改为下面这串吗

            int rr;
			int flag = 1;//默认走不了--flag是1表示走不了
			if (s.steps < k)rr = 2;
			if (s.steps >= k && s.steps < k * 2) rr = 1;
			if (s.steps >= 2 * k)rr = 0;
			for (int i = 0; i < 4; i++) {
				int ax = s.x + dx[i];
				int ay = s.y + dy[i];
				if (check(ax, ay, rr) && !visited[ax][ay]) {
					mque[tail++] = fat(ax, ay, s.steps + 1);
					visited[ax][ay] = 1;
                    flag = 0;
				}
			}
			//怎么写走不了的情况 -模拟走的所有可能-走不了的反面是有一条路可以走 
 
			//for (int i = 0; i < 4; i++) {
				//int ax = s.x + dx[i];
				//int ay = s.y + dy[i];
				//if (check(ax, ay, rr)&&!visited[ax][ay]) {
                //flag = 0;
					//break;
				//}
			//}
			if (flag) {//走不了,等待 
				mque[tail++] = fat(s.x, s.y, s.steps + 1);
			}

 上面这段代码是不对的,实现不了走和不走这两种状态的转换,最后导致代码逻辑和自己想的逻辑不一致的情况出现,还是分开写

经思考,我的代码思路实际上是,对每一步,都进行等待操作(出某个元素前进这个元素坐标的步数+1这种情况到队列中)和走操作(如果可以走的话),对内存消耗大

对于上面的代码,注意到,只要变成1*1的胖子后,肯定不需要等待,即

if(rr!=0)
    mque[tail++] = fat(r.x,r.y,r.steps+1);

这样,对于mque,需要的大小可以减少很多,经检验,减少到maxn*maxn*10就可以了(比这更小的没有测试,没必要再试了)

具体代码如下

//#include<bits/stdc++.h> 
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <algorithm>
#include <queue>
#include <stack>
#include <map>
#include <vector>
#include <cstring>//memset
#include <string>
using namespace std;
//const int maxn = 1e8;
bool IsPrime(int m) {
	if (m == 2)
		return true;
	int tmp = sqrt(m);
	for (int i = 2; i <= tmp; i++)
		if (m % i == 0)
			return false;
	return true;
}
int gcd_wx(int a, int b) {
	while (a != b)
	{
		if (a > b)
			a = a - b;
		else
			b = b - a;
	}
	return a;
}
bool leapYear(int y) {
	if (y % 400 == 0)
		return true;
	if (y % 4 == 0 && y % 100 != 0)
		return true;
	return false;
}
int dx[4] = { 1,0,0,-1 };
int dy[4] = { 0,-1,1,0 };
char dire[4] = { 'D','L','R','U' };
struct Step {
	int x;
	int steps;//第steps步走到位置x
	Step(int xx, int s) :x(xx), steps(s) {
	}
};
//queue<Step>q;
struct node {
	//输出最短路径的步数和路径 
	int x;
	int y;
	int front;//记录上一个节点
	int steps;
	char dir;
	node() :x(-1), y(-1), front(-1), steps(0), dir('w') {
	}
	node(int xx, int yy, int ff, int s, char d) :x(xx), y(yy), front(ff), steps(s), dir(d) {
	}
};
struct dish {
	string s;
	int steps;
	int front;
	int dir;
	dish() :s("aaaaaaaaaa"), steps(-1), front(-91), dir(-1) {
	}//定义这个用于vector<dish> dque(1000000) 
	dish(string ss, int s, int ff, int d) :s(ss), steps(s), front(ff), dir(d) {
	}//定义这个用于赋值构造 
};

const int maxn = 350;
char mp[maxn][maxn];
int visited[maxn][maxn];
struct fat {
	int x;
	int y;
	int steps;
	fat() :x(-1), y(-1), steps(-1) {
	}
	fat(int xx, int yy, int s) :x(xx), y(yy), steps(s) {
	}
};
int n, k;
vector<fat> mque(maxn* maxn*10);
bool check(int x, int y, int r) {//点(x,y)合法返回true,否则返回false 
	if (x + r > n || x - r<1 || y + r>n || y - r < 1)return false;
	for (int i = x - r; i <= x + r; i++)
		for (int j = y - r; j <= y + r; j++)
			if (mp[i][j] == '*')return false;
	return true;
}
int main() {
	cin >> n >> k;

	for (int i = 1; i <= n; i++)
	{
		string tmpString;
		cin >> tmpString;
		for (int j = 1; j <= n; j++)
			mp[i][j] = tmpString[j - 1];
	}
	mque[0] = fat(3, 3, 0);
	visited[3][3] = 1;
	int head = 0, tail = 1;
	while (head <= tail) {
		fat s = mque[head];
		if (s.x == n - 2 && s.y == n - 2) {
			cout << s.steps << endl;
			return 0;
		}
		else
		{
			int rr;
			//怎么写走不了的情况 -模拟走的所有可能-走不了的反面是有一条路可以走 
			int flag = 1;//默认走不了--flag是1表示走不了 
			if (s.steps < k)rr = 2;
			if (s.steps >= k && s.steps < k * 2) rr = 1;
			if (s.steps >= 2 * k)rr = 0;
			for (int i = 0; i < 4; i++) {
				int ax = s.x + dx[i];
				int ay = s.y + dy[i];
				if (check(ax, ay, rr) && !visited[ax][ay]) {
					//flag = 0;
					mque[tail++] = fat(ax, ay, s.steps + 1);
					visited[ax][ay] = 1;
				}
			}
			/*
			for (int i = 0; i < 4; i++) {
				int ax = s.x + dx[i];
				int ay = s.y + dy[i];
				if (check(ax, ay, rr)&&!visited[ax][ay]) {
					flag = 0;
					break;
				}
			}//上面这段代码必然会导致flag是0-- 
			
			if (flag) {//走不了,等待 
				mque[tail++] = fat(s.x, s.y, s.steps + 1);
			}
			*/
			if(rr!=0) 
			mque[tail++] = fat(s.x, s.y, s.steps + 1);
		}
		head++;
	}

	return 0;
}

学霸的作业

问题描述

  学霸抢走了大家的作业,班长为了帮同学们找回 作业,决定去找学霸决斗。但学霸为了不要别人打扰,住在一个城堡里,城堡外面是一个二维的格子迷宫,要进城堡必须得先通过迷宫。因为班长还有妹子要陪,磨 刀不误砍柴功,他为了节约时间,从线人那里搞到了迷宫的地图,准备提前计算最短的路线。可是他现在正向妹子解释这件事情,于是就委托你帮他找一条最短的路线。

输入格式

  第一行两个整数n, m,为迷宫的长宽。
  接下来n行,每行m个数,数之间没有间隔,为0或1中的一个。0表示这个格子可以通过,1表示不可以。假设你现在已经在迷宫坐标(1,1)的地方,即 左上角,迷宫的出口在(n,m)。每次移动时只能向上下左右4个方向移动到另外一个可以通过的格子里,每次移动算一步。数据保证(1,1),(n,m)可 以通过。

输出格式

  第一行一个数为需要的最少步数K。
  第二行K个字符,每个字符∈{U,D,L,R},分别表示上下左右。如果有多条长度相同的最短路径,选择在此表示方法下字典序最小的一个。

样例输入

Input Sample 1:
3 3
001
100
110

Input Sample 2:
3 3
000
000
000

样例输出

Output Sample 1:
4
RDRD

Output Sample 2:
4
DDRR

数据规模和约定

  有20%的数据满足:1<=n,m<=10
  有50%的数据满足:1<=n,m<=50
  有100%的数据满足:1<=n,m<=500。
 

广搜+字典序

记录广搜中的信息,可以将需要的信息,如点的坐标(搜索时需要,用来判断是否可以过去是否访问过是否过界),最短路径长度,上一个节点在队列中的位置,从上个节点走到该点的行走方向,放到一个struct中即可,队列每次拿出一个,按照字典序来扩展与拿出的点的相连的点,扩展的点加到队列中(同时tail指针后移),全部拓展后head指针++,表示该点出队列

了解字典序是什么即可,加了一个字典序,就是固定了遍历顺序,即在遍历时要按照字典序从小到大的顺序进行遍历就行了----遍历就是暴力搜索----此处有四个方向,类比四重循环,每层循环要求循环1-9,要求输出按照字典序从小到大输出,则每层按照1-9的顺序遍历即可。

记录最短路径,用到上面说的 上一个节点在队列中的位置,从上个节点走到该点的行走方向,即可。

自己编写的代码

经历的错误:输入的顺序是n和m,不是m和n,每行输入的是字符串,可以用C中char*或者C++中string,还有,由于是字符,所以判断能不能通过的时候,要么统一用字符‘0’与‘0’比较,要么统一化为数字比较,否则会出错。

获得path路径的一种写法

//#include<bits/stdc++.h> 
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <algorithm>
#include <queue>
#include <stack>
#include <map>
#include <vector>
#include <cstring>//memset
#include <string>
using namespace std;
//const int maxn = 1e8;
bool IsPrime(int m){
	if(m == 2)
		return true;
	int tmp = sqrt(m);
	for(int i = 2;i <= tmp;i++)
		if(m%i == 0)
			return false;
	return true;
}
int gcd_wx(int a,int b){
	while(a!=b)
	{
		if(a>b)
			a = a-b;
		else
			b = b-a;
	}
	return a;
}
bool leapYear(int y){
	if(y%400 == 0)
		return true;
	if(y%4 == 0&& y%100!= 0)
		return true;
	return false;
}
int dx[4] = {1,0,0,-1};
int dy[4] = {0,-1,1,0};
char dire[4] = {'D','L','R','U'};
struct Step{
	int x;
	int steps;//第steps步走到位置x
	Step(int xx,int s):x(xx),steps(s){
	}
};
//queue<Step>q;
struct node{
	//输出最短路径的步数和路径 
	int x;
	int y;
	int front;//记录上一个节点
	int steps; 
	char dir;
	node():x(-1),y(-1),front(-1),steps(0),dir('w'){
	}
	node(int xx,int yy,int ff,int s,char d):x(xx),y(yy),front(ff),steps(s),dir(d){
	}
}; 
int mp[510][510];
int visited[510][510];
char path[3000];
vector<node > que(3000); 
int main(){
	int m,n;
	cin>>n>>m;
	string s;
	for(int i = 0;i < n;i++)
	{
		cin>>s;
		for(int j = 0;j < m;j++)
			mp[i][j] = s[j] - '0';
	}
		
	que[0] = node(0,0,-1,0,'o');
	visited[0][0] = 1;
	int head = 0,tail = 1;
	while(head < tail){
		node r = que[head];
		if(r.x==n-1&&r.y == m-1){
			cout<<r.steps<<endl;
			int k = 0;
			while(true){
				path[k] = r.dir;
				r = que[r.front];
				if(r.front == -1) break;//到了起点接退出循环,否则继续,k++
				k++;
			}
			//k--;
			while(k>= 0){
				cout<<path[k];
				k--;
			}
			return 0;
		}
		else
		{
			for(int i = 0;i < 4;i++){
				int ax = r.x;
				int ay = r.y;
				ax+=dx[i];
				ay+=dy[i];
				if(ax>=n||ax<0||ay<0||ay>=m||visited[ax][ay]||mp[ax][ay]==1)continue;
				que[tail++] = node(ax,ay,head,r.steps+1,dire[i]);
				visited[ax][ay] = 1;
			}
		}
		head++;
	}
	
	return 0;
}

获得path路径的另一种写法

//#include<bits/stdc++.h> 
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <algorithm>
#include <queue>
#include <stack>
#include <map>
#include <vector>
#include <cstring>//memset
#include <string>
using namespace std;
//const int maxn = 1e8;
bool IsPrime(int m){
	if(m == 2)
		return true;
	int tmp = sqrt(m);
	for(int i = 2;i <= tmp;i++)
		if(m%i == 0)
			return false;
	return true;
}
int gcd_wx(int a,int b){
	while(a!=b)
	{
		if(a>b)
			a = a-b;
		else
			b = b-a;
	}
	return a;
}
bool leapYear(int y){
	if(y%400 == 0)
		return true;
	if(y%4 == 0&& y%100!= 0)
		return true;
	return false;
}
int dx[4] = {1,0,0,-1};
int dy[4] = {0,-1,1,0};
char dire[4] = {'D','L','R','U'};
struct Step{
	int x;
	int steps;//第steps步走到位置x
	Step(int xx,int s):x(xx),steps(s){
	}
};
//queue<Step>q;
struct node{
	//输出最短路径的步数和路径 
	int x;
	int y;
	int front;//记录上一个节点
	int steps; 
	char dir;
	node():x(-1),y(-1),front(-1),steps(0),dir('w'){
	}
	node(int xx,int yy,int ff,int s,char d):x(xx),y(yy),front(ff),steps(s),dir(d){
	}
}; 
int mp[510][510];
int visited[510][510];
char path[3000];
vector<node > que(3000); 
int main(){
	int n,m;
	cin>>n>>m;
	string s;
	for(int i = 0;i < n;i++)
	{
		cin>>s;
		for(int j = 0;j < m;j++)
			mp[i][j] = s[j] - '0';
	}
		
	que[0] = node(0,0,-1,0,'o');
	visited[0][0] = 1;
	int head = 0,tail = 1;
	while(head < tail){
		node r = que[head];
		if(r.x==n-1&&r.y == m-1){
			cout<<r.steps<<endl;
			int k = 0;
			while(true){
				if(r.front == -1) break;//到了起点退出,但是k已经++了
				path[k] = r.dir;
				r = que[r.front];
				k++;
			}
			k--;//k多1,要先减去
			while(k>= 0){
				cout<<path[k];
				k--;
			}
			return 0;
		}
		else
		{
			for(int i = 0;i < 4;i++){
				int ax = r.x;
				int ay = r.y;
				ax+=dx[i];
				ay+=dy[i];
				if(ax>=n||ax<0||ay<0||ay>=m||visited[ax][ay]||mp[ax][ay]==1)continue;
				que[tail++] = node(ax,ay,head,r.steps+1,dire[i]);
				visited[ax][ay] = 1;
			}
		}
		head++;
	}
	
	return 0;
}

并查集应用:

C国由n个小岛组成,为了方便小岛之间联络,C国在小岛间建立了m座大桥,每座大桥连接两座小岛。两个小岛间可能存在多座桥连接。然而,由于海水冲刷,有一些大桥面临着不能使用的危险。

  如果两个小岛间的所有大桥都不能使用,则这两座小岛就不能直接到达了。然而,只要这两座小岛的居民能通过其他的桥或者其他的小岛互相到达,他们就会安然无事。但是,如果前一天两个小岛之间还有方法可以到达,后一天却不能到达了,居民们就会一起抗议。

  现在C国的国王已经知道了每座桥能使用的天数,超过这个天数就不能使用了。现在他想知道居民们会有多少天进行抗议。

样例说明

  第一天后2和3之间的桥不能使用,不影响。
  第二天后1和2之间,以及1和3之间的桥不能使用,居民们会抗议。
  第三天后3和4之间的桥不能使用,居民们会抗议。

数据规模和约定

  对于30%的数据,1<=n<=20,1<=m<=100;
  对于50%的数据,1<=n<=500,1<=m<=10000;
  对于100%的数据,1<=n<=10000,1<=m<=100000,1<=a, b<=n, 1<=t<=100000。

输入
 输入的第一行包含两个整数n, m,分别表示小岛的个数和桥的数量。
  接下来m行,每行三个整数a, b, t,分别表示该座桥连接a号和b号两个小岛,能使用t天。小岛的编号从1开始递增。

输出
  输出一个整数,表示居民们会抗议的天数。

样例输入
4 4
1 2 2
1 3 2
2 3 1
3 4 3
样例输出
2
 

D. CCF 201703-4 地铁修建

【问题描述】

  A市有n个交通枢纽,其中1号和n号非常重要,为了加强运输能力,A市决定在1号到n号枢纽间修建一条地铁。
  地铁由很多段隧道组成,每段隧道连接两个交通枢纽。经过勘探,有m段隧道作为候选,两个交通枢纽之间最多只有一条候选的隧道,没有隧道两端连接着同一个交通枢纽。
  现在有n家隧道施工的公司,每段候选的隧道只能由一个公司施工,每家公司施工需要的天数一致。而每家公司最多只能修建一条候选隧道。所有公司同时开始施工。
  作为项目负责人,你获得了候选隧道的信息,现在你可以按自己的想法选择一部分隧道进行施工,请问修建整条地铁最少需要多少天。

【输入形式】

  输入的第一行包含两个整数nm,用一个空格分隔,分别表示交通枢纽的数量和候选隧道的数量。
  第2行到第m+1行,每行包含三个整数abc,表示枢纽a和枢纽b之间可以修建一条隧道,需要的时间为c天。

【输出形式】

  输出一个整数,修建整条地铁线路最少需要的天数。

【样例输入】

  6 6
  1 2 4
  2 3 4
  3 6 7
  1 4 2
  4 5 5
  5 6 6

【样例输出】

  6
【样例说明】

  可以修建的线路有两种。
  第一种经过的枢纽依次为1, 2, 3, 6,所需要的时间分别是4, 4, 7,则整条地铁线需要7天修完;
  第二种经过的枢纽依次为1, 4, 5, 6,所需要的时间分别是2, 5, 6,则整条地铁线需要6天修完。
  第二种方案所用的天数更少。

【评分标准】

  对于20%的评测用例,1 ≤ n ≤ 10,1 ≤ m ≤ 20;
  对于40%的评测用例,1 ≤ n ≤ 100,1 ≤ m ≤ 1000;
  对于60%的评测用例,1 ≤ n ≤ 1000,1 ≤ m ≤ 10000,1 ≤ c ≤ 1000;
  对于80%的评测用例,1 ≤ n ≤ 10000,1 ≤ m ≤ 100000;
  对于100%的评测用例,1 ≤ n ≤ 100000,1 ≤ m ≤ 200000,1 ≤ ab ≤ n,1 ≤ c ≤ 1000000。

  所有评测用例保证在所有候选隧道都修通时1号枢纽可以通过隧道到达其他所有枢纽。

初步代码dijkstra

//#include<bit/stdc++.h> 
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <algorithm>
#include <queue>
#include <stack>
#include <map>
#include <vector>
#include <cstring>//memset
#include <string>
using namespace std;
//const int maxn = 1e8;
bool IsPrime(int m) {
	if (m == 2)
		return true;
	int tmp = sqrt(m);
	for (int i = 2; i <= tmp; i++)
		if (m % i == 0)
			return false;
	return true;
}
int gcd_wx(int a, int b) {
	while (a != b)
	{
		if (a > b)
			a = a - b;
		else
			b = b - a;
	}
	return a;
}
bool leapYear(int y) {
	if (y % 400 == 0)
		return true;
	if (y % 4 == 0 && y % 100 != 0)
		return true;
	return false;
}
int dx[4] = { 1,0,0,-1 };
int dy[4] = { 0,-1,1,0 };
char dire[4] = { 'D','L','R','U' };
map<pair<int, int>, int> mp;
map<int, int> dis;
map<int, int> path;
map<int, int>visited;
int n, m;
int main() {
	cin >> n >> m;
	for (int i = 1; i <= m; i++) {
		int a, b, c;
		scanf("%d %d %d", &a, &b, &c);
		mp[{a, b}] = c;
	}
	for (int i = 2; i <= n; i++) {
		if (mp[{1, i}]) {
			dis[i] = mp[{1, i}];
			path[i] = 1;
		}
		else
		{
			dis[i] = 1 << 30;
			path[i] = -1;
		}
	}
	visited[1] = 1;
	for (int times = 1; times < n; times++) {
		int index = -1;
		for (int i = 2; i <= n; i++) {
			if(!visited[i]&&(index == -1||dis[i]<dis[index]))
				index = i;
		}
		visited[index] = 1;
		for (int i = 2; i <= n; i++) {
			if (!mp[{index, i}])continue;//不存在从i到index的路
			int tmpMaxLen = max(dis[index], mp[{index, i}]);
			if (!visited[i] && dis[i] > tmpMaxLen)
			{
				dis[i] = tmpMaxLen;
				path[i] = index;
			}
		}
	}
	cout << dis[n] << endl;
	return 0;
}

运行结果

 超时超内存

代码问题,无向图,i与j之间的路是无向的

下面代码错误

for (int i = 1; i <= m; i++) {
		int a, b, c;
		scanf("%d %d %d", &a, &b, &c);
		mp[{a, b}] = c;
	}

改为下面的 

for (int i = 1; i <= m; i++) {
		int a, b, c;
		scanf("%d %d %d", &a, &b, &c);
		mp[{a, b}] = c;
        mp[{b, a}] = c;
	}

 结果如下

目前不对本题作进一步探究

E. CCF 201609-4 交通规划

【问题描述】

       G国国王来中国参观后,被中国的高速铁路深深的震撼,决定为自己的国家也建设一个高速铁路系统。
  建设高速铁路投入非常大,为了节约建设成本,G国国王决定不新建铁路,而是将已有的铁路改造成高速铁路。现在,请你为G国国王提供一个方案,将现有的一部分铁路改造成高速铁路,使得任何两个城市间都可以通过高速铁路到达,而且从所有城市乘坐高速铁路到首都的最短路程和原来一样长。请你告诉G国国王在这些条件下最少要改造多长的铁路。

【输入形式】

       输入的第一行包含两个整数n, m,分别表示G国城市的数量和城市间铁路的数量。所有的城市由1到n编号,首都为1号。
  接下来m行,每行三个整数a, b, c,表示城市a和城市b之间有一条长度为c的双向铁路。这条铁路不会经过a和b以外的城市。

【输出形式】

      输出一行,表示在满足条件的情况下最少要改造的铁路长度。

【样例输入】

  4 5
  1 2 4
  1 3 5
  2 3 2
  2 4 3
  3 4 2

【样例输出】

  11

【样例说明】

       对于20%的评测用例,1 ≤ n ≤ 10,1 ≤ m ≤ 50;
  对于50%的评测用例,1 ≤ n ≤ 100,1 ≤ m ≤ 5000;
  对于80%的评测用例,1 ≤ n ≤ 1000,1 ≤ m ≤ 50000;
  对于100%的评测用例,1 ≤ n ≤ 10000,1 ≤ m ≤ 100000,1 ≤ a, b ≤ n,1 ≤ c ≤ 1000。输入保证每个城市都可以通过铁路达到首都。

【评分标准】

J. CCF 201604-2 俄罗斯方块

【问题描述】

  俄罗斯方块是俄罗斯人阿列克谢·帕基特诺夫发明的一款休闲游戏。
  游戏在一个15行10列的方格图上进行,方格图上的每一个格子可能已经放置了方块,或者没有放置方块。每一轮,都会有一个新的由4个小方块组成的板块从方格图的上方落下,玩家可以操作板块左右移动放到合适的位置,当板块中某一个方块的下边缘与方格图上的方块上边缘重合或者达到下边界时,板块不再移动,如果此时方格图的某一行全放满了方块,则该行被消除并得分。
  在这个问题中,你需要写一个程序来模拟板块下落,你不需要处理玩家的操作,也不需要处理消行和得分。
  具体的,给定一个初始的方格图,以及一个板块的形状和它下落的初始位置,你要给出最终的方格图。

【输入形式】

  输入的前15行包含初始的方格图,每行包含10个数字,相邻的数字用空格分隔。如果一个数字是0,表示对应的方格中没有方块,如果数字是1,则表示初始的时候有方块。输入保证前4行中的数字都是0。
  输入的第16至第19行包含新加入的板块的形状,每行包含4个数字,组成了板块图案,同样0表示没方块,1表示有方块。输入保证板块的图案中正好包含4个方块,且4个方块是连在一起的(准确的说,4个方块是四连通的,即给定的板块是俄罗斯方块的标准板块)。
  第20行包含一个1到7之间的整数,表示板块图案最左边开始的时候是在方格图的哪一列中。注意,这里的板块图案指的是16至19行所输入的板块图案,如果板块图案的最左边一列全是0,则它的左边和实际所表示的板块的左边是不一致的(见样例)

【输出形式】

  输出15行,每行10个数字,相邻的数字之间用一个空格分隔,表示板块下落后的方格图。注意,你不需要处理最终的消行。

【样例输入】

  0 0 0 0 0 0 0 0 0 0
  0 0 0 0 0 0 0 0 0 0
  0 0 0 0 0 0 0 0 0 0
  0 0 0 0 0 0 0 0 0 0
  0 0 0 0 0 0 0 0 0 0
  0 0 0 0 0 0 0 0 0 0
  0 0 0 0 0 0 0 0 0 0
  0 0 0 0 0 0 0 0 0 0
  0 0 0 0 0 0 0 0 0 0
  0 0 0 0 0 0 0 0 0 0
  0 0 0 0 0 0 0 1 0 0
  0 0 0 0 0 0 1 0 0 0
  0 0 0 0 0 0 1 0 0 0
  1 1 1 0 0 0 1 1 1 1
  0 0 0 0 1 0 0 0 0 0
  0 0 0 0
  0 1 1 1
  0 0 0 1
  0 0 0 0
  3

【样例输出】

  0 0 0 0 0 0 0 0 0 0
  0 0 0 0 0 0 0 0 0 0
  0 0 0 0 0 0 0 0 0 0
  0 0 0 0 0 0 0 0 0 0
  0 0 0 0 0 0 0 0 0 0
  0 0 0 0 0 0 0 0 0 0
  0 0 0 0 0 0 0 0 0 0
  0 0 0 0 0 0 0 0 0 0
  0 0 0 0 0 0 0 0 0 0
  0 0 0 0 0 0 0 0 0 0
  0 0 0 0 0 0 0 1 0 0
  0 0 0 0 0 0 1 0 0 0
  0 0 0 0 0 0 1 0 0 0
  1 1 1 1 1 1 1 1 1 1
  0 0 0 0 1 1 0 0 0 0

  • 0
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值