NCST 2018-2019秋季学期个人排位赛(二)

NCST 2018-2019秋季学期个人排位赛(二)

A : Lucky Word

题目

记录找最大最小,注意!运算符的优先级问题

#include
#include
#include
#define rep(i,a,b) for(int i=(a); i<(int)(b);++i)
#define _rep(i,a,b) for(int i=(a);i<=(int)(b);++i)
int main()
{
    int n;
    scanf("%d",&n);
    rep(i,0,n)
    {
        char c[105];
        int arr[26],tot1=0,tot2=0;
        memset(arr,0,sizeof(arr));
        scanf("%s",c);
        rep(i,0,strlen(c))
            ++arr[c[i]-'a'];

        std::sort(arr,arr+26);
        tot1=arr[25];
        tot2=arr[std::upper_bound(arr,arr+26,0)-arr];
        int ch=tot1-tot2,flag=0;

        if(ch==1||ch==0)
        {
            printf("No Answer\n0\n");
            continue;
        }
        _rep(i,2,sqrt(ch))
            if(!(ch%i))
                flag=1;
        if(flag)
            printf("No Answer\n0\n");
        else
            printf("Lucky Word\n%d\n",ch);
    }
    return 0;
}

B : 小A的烦恼

题目

找二进制的一,方法很多,这里给出位运算法, 扩展

#include
#define rep(i,a,b) for(int i=(a); i<(int)(b);++i)
int fun(int a)
{
    int k=0;
    while(a)
    {
        a=a&(a-1);
        ++k;
    }
    return k;
}
int main()
{
    int n;
    scanf("%d",&n);
    rep(i,0,n)
    {
        int a,b,c,d;
        scanf("%d%d%d%d",&a,&b,&c,&d);
        printf("%d %d %d %d\n",fun(a),fun(b),fun(c),fun(d));
    }
    return 0;
}

C : 赛跑

题目

T × Y = X × M + X × T ⇒ T = X × M Y − X {{T}\times{Y}={X}\times{M}+{X}\times{T}} \Rightarrow {T=\frac{{X}\times{M}}{Y-X}} T×Y=X×M+X×TT=YXX×M
T {T} T:时间
X {X} X :先跑的速度
Y {Y} Y:追的速度

注意一下不要用int除,会有除不尽的方案

#include
#define rep(i,a,b) for(int i=(a); i<(int)(b);++i)
int main()
{
    int n;
    scanf("%d",&n);
    rep(i,0,n)
    {
        int m,x,y,z;
        scanf("%d %d %d %d",&m,&x,&y,&z);
        int t=1.0*x*m/(y-x);
        float ans=z*t;
        printf("%.2f\n",ans);
    }
    return 0;
}

D : Catch My Pet

题目

这个题最开始做是写的递归,因为出口找不到试了很多很多次也不对,后来去查的发现是bfs,还是自己思考的少(本来就蒟蒻还不动脑子,没救了),不光是递归出口找不到,而且在我写递归的时候还在念叨找到就结束找到就结束,这不就是bfs嘛,对自己学过的东西没有印象,没有总结过每种方法的特点,做题依然抓瞎。

这题有很多的方法,先上bfs的

#include
#include
#define rep(i,a,b) for(int i=(a); i<(int)(b);++i)
using namespace std;
const int maxn=100001;
int n,k,book[maxn],step[maxn];

void bfs()
{
    int head,next;
    q.push(n);
    step[n]=0;
    book[n]=1;
    while(!q.empty())
    {
        head=q.front();
        q.pop();
        rep(i,0,3)//三方向
        {
            switch(i)
            {
                case 0:next=head+1;break;
                case 1:next=head-1;break;
                case 2:next=head*2;break;
            }
            if(next>=0&&next<=maxn&&!book[next])
            {
                q.push(next);
                book[next]=1;
                step[next]=step[head]+1;
                if(next==k)
                {
                    printf("%d\n",step[k]);
                    break;
                }
            }
        }
    }
}

int main()
{
    scanf("%d %d",&n,&k);
    if(n>=k)
        printf("%d\n",n-k);
    else
        bfs();
    return 0;
}

正着递归(数大输出不了答案),这样写有很多不好考虑到的情况,比如把移动顺序改一改可能就输出不了

#include
int n,k,ans=0x3f3f3f3f;
int book[100005];

void fun(int pos,int step)
{
    if(pos<0||step>ans||pos>2*k||book[pos])
        return;
    if(pos==k)
    {
        if(step<ans)
            ans=step;
        return;
    }
    book[pos]=1;
    if(pos>k)
        fun(pos-1,step+1);
    fun(pos+1,step+1);
    book[pos]=0;
    fun(pos-1,step+1);
    book[pos]=0;
    fun(pos*2,step+1);
}

int main()
{
    scanf("%d %d",&n,&k);
    if(n>=k)
        printf("%d\n",n-k);
    else
    {
        fun(n,0);
        printf("%d\n",ans);
    }
    return 0;
}

反着递归,也就是从终点向起点递归,写多了会发现其实这个题还是二分的,找最近的偶数,看是先减步数少还是先加步数少,反着递归应该也能避免顺序问题

#include
int n,k,ans=0x3f3f3f3f;
int book[100005];

void fun(int pos,int step)
{
    if(pos<0||book[pos]||step>ans)
        return;
    if(pos==n)
    {
        if(step<ans)
            ans=step;
        return;
    }
    book[pos]=1;
    if(pos%2==0)
        fun(pos/2,step+1);
    fun(pos+1,step+1);
    book[pos]=0;
    fun(pos-1,step+1);
}

int main()
{
    scanf("%d %d",&n,&k);
    if(n>=k)
        printf("%d\n",n-k);
    else
    {
        fun(k,0);
        printf("%d\n",ans);
    }
    return 0;
}

这种方法稍大一点数也能通过,不过再大也是运行不出来(是不是爆栈了???)

爆炸那改成尾递归试试(我不会写,这是腾大佬给我发的,还没看懂)

#include
#include
int n,k;

int fun(int pos)
{
    if(n>=pos)//递归终点
        return n-pos;
    if(pos%2==0)
        return std::min(pos-n,fun(pos/2)+1);//看是减半离的近还是直接减离的近
    else
        return std::min(fun(pos+1),fun(pos-1))+1;
}

int main()
{
    scanf("%d %d",&n,&k);
    printf("%d\n",fun(k));
    return 0;
}

这个数大也能对,就是理解不了(为啥加1啊,加1就是次数吗?脑补:因为最后找到返回的是0,所以加1也确保一定是最小的,于是这里加1就可以代表次数了。昨天刚写了分治,今天就不会了)
还要感谢范学长的指导

所以bfs才是这题最好的解法(蒟蒻的微笑( ^ _ ^ ))

之所以bfs和递归差这么大,其实就是bfs只会把合法的点加入判断序列,而递归中所有的点都在序列里,虽然会被return但是数量实在太大,所以运行很成问题

E : 水池数目

题目

标准dfs,也就是填色法,一个负数代表一种颜色,用负数不用正数就是防止给你的矩阵里有别的正数

#include
#include
#define rep(i,a,b) for(int i=(a); i<(int)(b);++i)
#define _rep(i,a,b) for(int i=(a);i<=(int)(b);++i)
const int maxn=100+5;
const int dir[4][2]={0,1,1,0,0,-1,-1,0};
int n,m,maze[maxn][maxn],book[maxn][maxn];

void dfs(int x,int y,int id)
{
    rep(k,0,4)
    {
        int tx=x+dir[k][0];
        int ty=y+dir[k][1];
        if(tx<1||tx>n||ty<1||ty>m)
            continue;
        if(book[tx][ty]||!maze[tx][ty])
            continue;
        book[tx][ty]=id;
        dfs(tx,ty,id);
    }
}

int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
        memset(book,0,sizeof(book));
        memset(maze,0,sizeof(maze));
        scanf("%d %d",&n,&m);
        _rep(i,1,n)
            _rep(j,1,m)
                scanf("%d",&maze[i][j]);
        int cnt=0;
        _rep(i,1,n)
            _rep(j,1,m)
                if(maze[i][j]==1&&book[i][j]==0)
                    dfs(i,j,--cnt);
        printf("%d\n",cnt*(-1));
    }
    return 0;
}

你可能感兴趣的:(NCSTOJ,算法,DFS,递归,BFS,NSCT)