其他分享
首页 > 其他分享> > 第十二届蓝桥杯大赛软件赛省赛

第十二届蓝桥杯大赛软件赛省赛

作者:互联网

试题A:卡片


题解

#include<bits/stdc++.h>
using namespace std;
int a[10];
bool check(int x){
	while(x){
		int t=x%10;
		if(!a[t])return false;
		--a[t];
		x/=10;
	}
	return true;
}
int main(){
	for(int i=0;i<10;++i)a[i]=2021;
	int ans=0;
	while(1){
		++ans;
		if(!check(ans))break;
	}
	cout<<ans-1;
	return 0;
}

答案:3181

试题B:直线


题解

法一

手动设置精度,小于该精度即认为相等

#include<bits/stdc++.h>
using namespace std;
#define db double
struct no{
	int x,y;
	no(int a,int b):x(a),y(b){}
};
db eps=1e-6;
vector<no>point;
vector<pair<db,db>>ans;
int main(){
	for(int i=0;i<20;++i)
	for(int j=0;j<21;++j){
		point.push_back(no(i,j));
	}
	int tot=point.size();
	for(int i=0;i<tot;++i)
	for(int j=i+1;j<tot;++j){
		db x1=point[i].x,y1=point[i].y;
		db x2=point[j].x,y2=point[j].y;
		if(x1==x2||y1==y2)continue;
		db k=(y1-y2)/(x1-x2);
		db b=y1-k*x1;
		int flag=1;
		for(int c=0;c<ans.size();++c){
			if(fabs(k-ans[c].first)<eps&&fabs(b-ans[c].second)<eps){
				flag=0;break;
			}
		}
		if(flag)ans.push_back(make_pair(k,b));
	}
	cout<<ans.size()+20+21;
	return 0;
}

法二

修改b的表达式:\(b=\frac{y_2*x_1-y_1*x_2}{x_1-x_2}\),就像\(\frac{2}{3} = \frac{4}{6}\)防止误差产生。

#include<bits/stdc++.h>
using namespace std;
#define db double
struct no{
	int x,y;
	no(int a,int b):x(a),y(b){}
};
db eps=1e-6;
vector<no>point;
set<pair<db,db>>ans;
int main(){
	for(int i=0;i<20;++i)
	for(int j=0;j<21;++j){
		point.push_back(no(i,j));
	}
	int tot=point.size();
	for(int i=0;i<tot;++i)
	for(int j=i+1;j<tot;++j){
		db x1=point[i].x,y1=point[i].y;
		db x2=point[j].x,y2=point[j].y;
		if(x1==x2||y1==y2)continue;
		db k=(y1-y2)/(x1-x2);
		db b=(y2*x1-y1*x2)/(x1-x2);
		int flag=1;
		ans.insert({k,b});
	}
	cout<<ans.size()+20+21;
	return 0;
}

答案:40257

试题C:货物摆放


题解
数字超级大,但质因数只有8个,因数只有128个,暴力枚举即可
顺便说一下因数个数等于不同质因数的指数分别加1后相乘的积

#include<bits/stdc++.h>
using namespace std;
#define ll long long 
const ll N=2021041820210418;
//const ll N=4;
ll prime[100],cntp;
set<ll>factor;
void get_p(){
	ll x=N;
	for(int i=2;i*i<=x;++i){
		while(x%i==0)prime[cntp++]=i,x/=i;
	}
	if(x)prime[cntp++]=x;//分解质因数
}
void dfs(int p,int n,int tot,ll num){//p当前位置,n已选个数,tot总长度
	if(tot==n){
		factor.insert(num);
		return ;
	}
	for(int i=p;i<cntp;++i){
		dfs(i+1,n+1,tot,num*prime[i]);
		dfs(i+1,n,tot,num);
	}
	return ;
}
int main(){
	get_p();
	cout<<"质因数个数:"<<cntp<<endl;
	for(int i=0;i<cntp;++i)cout<<prime[i]<<" ";
	factor.insert(1);
	for(int len=1;len<=cntp;++len){
		dfs(0,0,len,1);//找因数
	}
	cout<<endl<<"因数个数:"<<factor.size();
	int ans=0;
	for(auto i:factor)//开始暴力枚举
	for(auto j:factor)
	for(auto k:factor){
		if(i*j*k==N)++ans;
	}
	cout<<endl<<"答案:"<<ans;
	return 0;
}

答案:

试题D:路径


题解
求最短路常用的三种方法:
  1.弗洛伊德(Floyd-Warshall algorithm)多源最短路
  2.spfa(贝尔曼福特(Bellman-Ford)的队列优化)单源最短
  3.迪杰斯特拉(Dijkstra)单源最短
这里贴一个dijkstra

#include<bits/stdc++.h>
using namespace std;
const int N=2050;
struct no{
	int x,id;
	no(int a,int b):id(a),x(b){}
	no(){}
	const bool operator<(const no&a)const{
		return x>a.x;//与小根堆配套使用
	}
};
int gcd(int a,int b){
	return b?gcd(b,a%b):a;
}
int g[N][N],dis[N],book[N];
priority_queue<no>q;
void dij(){
	dis[1]=0;
	q.push(no(1,0));
	while(q.size()){
		no now=q.top();
		q.pop();
		if(book[now.id])continue;
		book[now.id]=1;
		for(int i=1;i<=2021;++i){
			if(dis[i]>dis[now.id]+g[now.id][i]){
				dis[i]=dis[now.id]+g[now.id][i];
				q.push(no(i,dis[i]));
			}
		}
	}
}
int main(){
	memset(dis,0x3f,sizeof(dis));
	memset(g,0x3f,sizeof(g));
	for(int i=1;i<=2021;++i)
	for(int j=i+1;j<=i+21;++j){
		g[i][j]=i*j/gcd(i,j);
		g[j][i]=g[i][j];
	}
	dij();
	cout<<dis[2021];
	return 0;
}

答案:10266837

试题E:回路计数


题解

状压 dp 是动态规划的一种,通过将状态压缩为整数来达到优化转移的目的。 ---OI Wiki
状态压缩的思想是用二进制来表示状态。用一个整数的二进制形式的每一个0或1表示一个状态。

f[i][j]表示当前处在点i状态为j

#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int N=21;
const int M=1<<N;
int g[N][N];
int gcd(int a,int b){
	return b?gcd(b,a%b):a;
}
ll f[N][M];
int main(){
	for(int i=0;i<N;++i)
	for(int j=i+1;j<N;++j){
		if(gcd(i+1,j+1)==1)g[i][j]=g[j][i]=1;
	}
	f[0][1]=1;
	for(int i=2;i<M;++i)//从小到大遍历每一种状态
	for(int j=0;j<N;++j){
		if((i&(1<<j))==0)continue;
		for(int k=0;k<N;++k){
			if((i&(1<<k))==0||j==k)continue;
			if(g[j][k]) f[j][i]+=f[k][i-(1<<j)];
		}
	}
	ll ans=0;
	for(int i=1;i<N;++i)ans+=f[i][M-1];
	cout<<ans;
	return 0;
}

注意==优先级高于&

答案:881012367360
剩下的明天再写

标签:const,no,赛省赛,第十二届,蓝桥,int,now,id,dis
来源: https://www.cnblogs.com/hetailang/p/15852058.html