8.7 模拟

第一题
现在有M个凳子排成一个圈,我们顺时针给凳子依次编号为1,2,3……,M。我们从编号为S的凳子开始,每次先顺时针数N个凳子,将第N个凳子搬走,然后再逆时针数K个凳子,将第K个凳子搬走。每次都这样先顺时针数N个,再逆时针数K个,直到只剩1个凳子,直接搬走。最后,我们想知道M个凳子的搬走顺序。
输入
共4行,每行1个数,分别表示题目中的M,S,N,K。

分析
经典约瑟夫问题+创新
逆时针即等于顺时针转了n-k%n嘛
然后主体随便搞搞就好了
模拟

#include <iostream>
#include <cstdio>
using namespace std;
int m,s,n,k,i,l;
int a[1002];
int main()
{
    scanf("%d%d%d%d",&m,&s,&n,&k);
    for (i=1;i<=m;i++)
    a[i]=i;
    n--;
    while (a[1]!=0)
    {
        if (l) 
        {
            l--;
            s=s+(m-k%m);
        }
        else
        {
            l++;
            s=s+(n%m);
        }
        s=(s-1)%m+1;
        printf("%d ",a[s]);
        for (i=s;i<=m;i++)
        a[i]=a[i+1];
        m--;
    }
}

第二题
这里写图片描述

分析
这题讲真挺水的
总之推规律,我不懂公式代表的意思,但是我总结出来了
以下皆为整除
b a
∑b/i - ∑a/i
i=1 i=1
得出的是a+1到b之间所有约数的个数,所以开始的时候a-1就行了

#include <iostream>
#include <cstdio>
using namespace std;
int i,a,b,sa,sb;
int main()
{
    scanf("%d%d",&a,&b);
    a--;
    for (i=1;i<=a;i++)
    sa+=a/i;
    for (i=1;i<=b;i++)
    sb+=b/i;
    printf("%d",sb-sa);
}

第三题
自从省队NOI赛前集训在scz举行之后,一个名叫cs1.6.exe的文件开始在机房广泛使用起来。每天大家都要找神犇小X借移动硬盘,考里面的这个文件。
由于机房里需要考这个文件的人太多了,每天都要花一段时间一个人一个人的去拷贝。小T觉得这实在是太麻烦了,就想找一个一劳永逸的方法。
小T调查了一下,机房有n台机器,且有局域网,所有机器通过一些网线连接起来,其整个布局是一个树形结构,即任意两台机器间都有且仅有一条路径。小T想在其中某一台机器上储存这个文件,需要的同学就可以直接通过局域网来下载这个文件。
网络上信息传输是需要时间的,我们定义两台机器间数据传输的时间为连接这两台机器的路径所包含的网线数量。虽然机房里通过局域网传个文件是很快的,但对于急不可耐的同学们来说,一分一秒都是宝贵的,文件传输越快越好。所以小T要选择一台机器存储文件,使得所有机器下载这个文件需要的总时间(即最后一台机器完成下载的时间)尽可能短。
现在,你需要给出这个最短时间,以便让小T看看他的决策是否最优。

Input
从selc.in中读入数据。
第1行:一个整数n。
第2~n行:两个整数u、v,即u、v两台机器间有一条网线连接。机器从1~n编号。
输入数据保证是一个连通的树型结构。

分析
是一题求树上最长链,然后取半的题目
讲真这题坑了我不少正确率然后发现是题库问题。。
树上最长链的一个特性就是任取一点求距离它最远的点,得出的点必是其一端端点
那么只要用DFS取搜个两遍就好了,用队列优化是O(n)吧,貌似
那么就没啥问题了,是吧
反正我不会讲队列那神秘复杂的东东

#include <iostream>
#include <cstdio>
using namespace std;
int n,i,k,u[100001],v[100001],sign[100001],list[100001],mlen,mpoi;
void dfs(int now,int dep,int pre)
{
    int i=list[now];
    if (dep>mlen)
    {
        mlen=dep;
        mpoi=now;
    }
    while (i>0)
    {
        if (u[i]!=pre)
        dfs(u[i],dep+1,now);
        i=sign[i];
    }
}
int main()
{
    scanf("%d",&n);
    for (i=1;i<=n-1;i++)
    {
        k++;
        scanf("%d%d",&u[k],&v[k]);
        sign[k]=list[u[k]];
        list[u[k]]=k;
        k++;
        u[k]=v[k-1];
        v[k]=u[k-1];
        sign[k]=list[u[k]];
        list[u[k]]=k;
    }
    dfs(1,0,0);
    mlen=0;
    dfs(mpoi,0,0);
    printf("%d",(mlen+1)/2);
}

第四题
当WJ醒来时,发现自己被困在一个地图的左上角,幸好WJ有张图,并了解到出口正是迷宫的右下角,至少有一条路径可以到达出口。
整个地图有些地方会有障碍(保证左上角右下角没有),WJ可以快速奔跑,只是需要拐弯时令人很不爽。为了保持心情愉悦,WJ想知道最少需要几次转弯。

Input
第一行两个数r,c表示地图大小
接下来r行,每行c个字符,‘*’代表此处有障碍,‘0’代表空地。

分析
为什么我感觉这题那么水呢
其实就是BFS,然后每次BFS判断到一个方向的时候一路走到底,在大队列中生成一个小队列,小队列在撞到墙以后结束

没了

#include <iostream>
#include <cstdio>
using namespace std;
int n,m,i,j,dx[4]={1,-1,0,0},dy[4]={0,0,-1,1},state[250001][3];
bool a[501][501];
char c;
int RP;
void in()
{
    scanf("%d%d\n",&n,&m);
    for (i=1;i<=n;i++)
    {
        for (j=1;j<=m;j++)
        {
            scanf("%c",&c);
            if (c=='*')
            a[i][j]=1;
        }
        scanf("%c",&c);
    }
}
bool pd(int x,int y)
{
    if (x<1||x>n||y<1||y>m) return 1;
    if (a[x][y]) return 1;
    return 0;
}
void bfs()
{
    int head=0,tail=1,i,x;
    state[1][0]=1;state[1][1]=1;a[1][1]=1;
    do
    {
        head++;
        for (i=0;i<=3;i++)
        if (!pd(state[head][0]+dx[i],state[head][1]+dy[i]))
        {
            x=head;
            while (!pd(state[x][0]+dx[i],state[x][1]+dy[i]))
            {
                tail++;
                state[tail][0]=state[x][0]+dx[i];
                state[tail][1]=state[x][1]+dy[i];
                state[tail][2]=state[head][2];
                a[state[tail][0]][state[tail][1]]=1;
                if (state[tail][0]==n&&state[tail][1]==m)
                {
                    printf("%d\n",state[tail][2]);
                    return;
                }       
                x=tail;
                state[tail][2]++;
            }
        }
    }
    while (head!=tail);
}
int main()
{
    in();
    bfs();
    RP++;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值