0309南京理工机试模拟考(二)

第二次

第二次模拟考的算法考点预告:并查集、BFS、Tarjan、动态规划之斐波那契数列。

1.P1012 拼数

A 拼数 https://www.luogu.com.cn/problem/P1012在这里插入图片描述
分析:此题最关键的是cmp函数,有点难想
方法一
考点:冒泡排序,string字符串类型的使用

#include<stdio.h>
#include<string>
#include<string.h>
#include<algorithm>
using namespace std;

/*---1-----*/
string a[20];

bool cmp(string a,string b){
	if(a+b>b+a) return true;
	return false;
}
void swap(string &a,string &b){
	string temp=a;
	a=b;
	b=temp;
}
int main(){
	int n;
	cin>>n;
	for(int i=0;i<n;i++) cin>>a[i];
	for(int i=0;i<n-1;i++){
		for(int j=0;j<n-1-i;j++){
			if(cmp(a[j],a[j+1])==false){
				swap(a[j],a[j+1]);
			}
		}
	}
	for(int i=0;i<n;i++) cout<<a[i];
} 

方法二
代码来源
使用sort方法,只需写一个cmp函数

#include<iostream>
#include<string>
#include<algorithm>//提供sort 
using namespace std;
string s[25];//不多说 
int n;//限制数字个数 

bool cmp(string a,string b) {
    return a+b>b+a;//自定义排序函数,这一步非常巧妙,假设a=321,b=32;a+b=32132,b+a=32321这样下面sort排下来就是32>321避免出现32132>32321的情况 
}
/*如果这样写:
bool cmp(string a,string b){
    return a>b;
    会发生321>32的情况,具体原因是字符串自己的关系运算是这样设定的 
}*/
int main() {
    cin>>n;
    for(int i=1; i<=n; i++) cin>>s[i];
    sort(s+1,s+n+1,cmp);//神来之笔 
    for(int i=1; i<=n; i++) cout<<s[i];//完美收场(yo)! 
    return 0;
}

2.P1308

B 统计单词数 https://www.luogu.com.cn/problem/P1308
在这里插入图片描述

#include<iostream>
#include<stdio.h>
#include<string>
#include<string.h>
#include<algorithm>
#include<cctype>
using namespace std;
/*------2------*/
bool equal(char a[],char b[]){
	if(strlen(a)!=strlen(b)) return false;
	for(int i=0;i<strlen(a);i++){
		if(a[i]!=b[i]) return false;
	}
	return true;
}
void change(char *a){
	int len =strlen(a);
	for(int i=0;i<len;i++){
		if(isupper(a[i])) a[i]=a[i]+32;
	}
}
int main(){
//	freopen("in.txt","r",stdin); 
	char a[100],b[1000],temp[100],c;
	scanf("%s",&a);
	change(a);
	int lena=strlen(a);
	getchar();
	int lenb=0,temp_len=0,ans=0,loc=-1;
	while((c=getchar())!=EOF){
		if(c=='\n') break;
		if(isupper(c)) c=c+32;
		lenb++;
		if(c==' '){
			temp[temp_len]='\0';
//			printf("%s-------%s",a,temp);
			if(equal(a,temp)) {
				ans++;
				if(loc==-1){
					loc=lenb-temp_len-1;
				}
			}
			temp_len=0;	
		}
		else{
			temp[temp_len]=c;
```cpp
			temp_len++;
		}
	}
	//如果最后一个单词temp是a(因为没有空格所以没有被判断)
	if(equal(a,temp)) ans++;
	if(loc==-1) printf("-1");
	else printf("%d %d",ans,loc);
//	fclose(stdin);
}

注意

	while((c=getchar())!=EOF){
		//下面句也可以不要
		if(c=='\n') break;

这种写法既可以文件输入,也可以cmd中输入,都正确

但下面这种

while((c=getchar())!='\n'){
}

这种写法只能cmd命令行读取,因此这种写法读取文件时,文件结尾是-1(宏定义中的EOF值),并不是换行符!且这种写法,代码机器判别结果是RE(runtime error)超时,可知测试集也没有 ’ \n ’

方法二
<cctype>的isupper()函数
<string.h>的strstr(str1,str2)函数,返回str1中第一次出现str2的位置(从0开始),
定义:strstr(str1,str2) 函数用于判断字符串str2是否是str1的子串。如果是,则该函数返回str2在str1中首次出现的地址;否则,返回NULL。
<stdio.h>中的gets()函数,
在这里插入图片描述
gets()遇换行结束,并且自动丢弃换行符,可吸收空格。

#include <cstring>
#include <cctype>
#include <cstdio>

void strlower (char *a) {//手写函数,将大写字母转换成小写字母
    for(int i = 0; a[i]; i ++ ) {
        if(isupper(a[i])) a[i] = tolower(a[i]);//isupper是判断是否是大写字母的系统函数,tolower是将其转换成小写字母的函数
    }
}

int main () {

    char destination[1000001], *q, source[11], *p;//destintion是要找的文章,source是要找的单词,p和q都是指针类,分别代表当前搜索到什么地方了和最后一次找到单词的指针
    bool flag = false;//判断是否找到了
    int ans = 0, ans1 = -1;//个数和首次出现的位置,ans1的初值是-1是因为在没找到的时候就直接输出就行了,省事

    gets(source);
    gets(destination);//输入

    strlower(destination);//全部转换成小写字母
    strlower(source);

    int len = strlen(source);//长度,在后面防止越界和加快速度

    p = destination;//先将指针设为全部

    for(; q = strstr(p, source); ) {//循环,strstr是在一个字符串里面给定一个字符串,寻找有没有这个字符串,若有,返回首次出现的指针否则返回NULL(空指针)
        if( q != NULL//找到了 
        && ( q == destination || *(q - 1) == ' ') //第一个条件是防止越界,第二个是判断前一个是不是空格
        && ( *(q + len) == '\0' || *(q + len) == ' ' ) ) {//如果后面也是空格
            ans ++ ;//答案加一
            if(flag == false) {//如果是首次找到
                flag = true;
                ans1 = q - destination;//第一个位置
            }
        }
        p = q + len+1;//刷新指针
    }

    if(flag == true)//找到了
        printf("%d %d" , ans, ans1);//输出
    else 
        printf("%d", ans1);//输出-1

    return 0;
}

C 01迷宫 https://www.luogu.com.cn/problem/P1141
在这里插入图片描述

方法一
自己的代码,三个点超时,和第二个代码相比,主要是每次检测新的点都会重新DFS,没有利用之前的搜索结果。其实在同一个连通分量里面的点可到达的点的数量是相同的。

const int maxn=10000;
bool inq[maxn][maxn]={false};
int matrix[maxn][maxn];
int ans,m,n;
char num[10000];
bool judge(int x,int y,int a){
	if(x<0||y<0||x>=n||y>=n) return false;
	if(inq[x][y]==true||matrix[x][y]==a) return false;
	return true;
}
int X[4]={0,0,-1,1};
int Y[4]={1,-1,0,0};
void DFS(int x,int y){
	for(int i=0;i<4;i++){
		int newx=x+X[i];
		int newy=y+Y[i];
		int a=matrix[x][y];
		if(judge(newx,newy,a)){
			inq[newx][newy]=true;
			ans++;
//			printf("(x,y):%d,%d",newx,newy);
			DFS(newx,newy);
		}
	}
}
int main(){
	scanf("%d%d\n",&n,&m);
	for(int i=0;i<n;i++){
//		scanf("%d",&matrix[i][j]);
//		scanf("%s",&num);
//		getchar();
		gets(num);		
//		printf("====%s****",num);
		for(int j=0;j<n;j++){
			matrix[i][j]=num[j]-'0';
		}
	}
	while(m--){

		int x,y;
		scanf("%d %d",&x,&y);
		inq[x-1][y-1]=true;
		ans=1;
		DFS(x-1,y-1);
		printf("%d\n",ans);
		for(int i=0;i<n;i++){
			for(int j=0;j<n;j++){
				inq[i][j]=false;
			}
		}
	}

}

方法二:
代码来源
利用了同一个连通分量里的点可以访问的点数相同,利用f[r][c]记录这个点在要求m个点的ans时,曾经第i次访问过。后面第j个点,若在同一个连通分量里,就可以利用这个结果,ans[ j ] ans[ i ]= ans[ f[r][c] ]

#include<cstdio>
#include<cstring>
int n,m,ans[100002],x,y,f[1002][1002];
char s[1002][1002];
void dfs(int r,int c,int z,int lll){
    if (r<0 || r>=n || c<0 || c>=n || f[r][c]!=-1 || s[r][c]-'0'!=z)return;
    f[r][c]=lll;ans[lll]++;
    dfs(r-1,c,!z,lll);dfs(r+1,c,!z,lll);dfs(r,c-1,!z,lll);dfs(r,c+1,!z,lll);
}
int main()
{
    scanf("%d%d",&n,&m);
    for (int i=0;i<n;i++)
    scanf("%s",s[i]);
    memset(f,-1,sizeof(f));
    for (int i=0;i<m;i++)
    {
        scanf("%d%d",&x,&y);x--;y--;
        if (f[x][y]==-1)dfs(x,y,s[x][y]-'0',i);else ans[i]=ans[f[x][y]];
    }
    for (int i=0;i<m;i++)
    printf("%d\n",ans[i]);
    return 0;
}

D 台阶问题 https://www.luogu.com.cn/problem/P1192
方法一:
利用了借鉴的数学方法。
代码借鉴

以下自己的递归方法80分,缺点是递归层数太高时,不能得到结果。例如

#include<string.h>
#include<cstdio>
int N,K;
 int mod=100003,a[1000000];
 int f(int n){
 	//如果到第n个台阶的方法总数之前计算过 
 	if(a[n]!=-1) return a[n];
 	if(n<=K) a[n]=2*f(n-1)%mod;
 	else a[n]=(2*f(n-1)-f(n-K-1))%mod;
	return a[n];
}
int main(){

	memset(a,-1,sizeof(a));
	a[0]=a[1]=1;
	scanf("%d %d",&N,&K);
	printf("%d",f(N));
}

方法二
分析:从前往后计算,每一个阶梯的方法,都是t[i-1]+…+t[i-k],且需判断减后i-j>=0

#include <bits/stdc++.h>
using namespace std;
int main()
{
    int i,j,n,k;
	int t[100009];
    memset(t,0,sizeof(t));
    
    cin>>n>>k;
    t[0]=1;
    for(i=1;i<=n;i++)
    {
        for(j=1;j<=k;j++)
        {
            if(i>=j)
            {
                t[i]+=t[i-j];
                t[i]=t[i]%100003;
            }
        }
    }
    cout<<t[n];
    return 0;
}

E 修复公路 https://www.luogu.com.cn/problem/P1111
在这里插入图片描述

考点:并查集

const int maxn=1010;
int n,m,father[maxn],num,ans=-1;
bool isBoot[maxn];
struct info{
	int a,b,t;
}in[100000];
bool cmp(info a,info b){
	return a.t<b.t;
}
int findFather(int x){
	int a=x;
	while(x!=father[x]){
		x=father[x];
	}
	//此时x是根节点 
	while(a!=father[a]){
		int z=a;
		a=father[a];
		father[z]=x;
	}
}
void init(int n){
	//n个村庄初始化
	for(int i=1;i<=n;i++){
		father[i]=i;
		isBoot[i]=false;
	} 
	//集合个数是n; 
	num=n;
}
void Union(int a,int b){
	int fa=findFather(a);
	int fb=findFather(b);
	if(fa!=fb){
		father[fa]=fb;
		num--;
	}
} 
int main(){
//	freopen("in.txt","r",stdin);
	scanf("%d%d",&n,&m);
	init(n);
	for(int i=0;i<m;i++){
		scanf("%d%d%d",&in[i].a,&in[i].b,&in[i].t); 
	}
	sort(in,in+m,cmp);
	for(int i=0;i<m;i++){
		int A=in[i].a;
		int B=in[i].b;
		Union(A,B);
		if(num==1){
			ans=in[i].t;
			break;
		}
	}
	printf("%d",ans);
//	fclose(stdin);
}

F 炸铁路 https://www.luogu.com.cn/problem/P1656
考点:tarjon/SPFA
不会

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值