HFOIer4.22题解

来源:互联网 发布:ubuntu mxnet 编辑:程序博客网 时间:2024/06/11 14:20

题目见此处:  http://blog.csdn.net/leizhehan/article/details/70492339 

本蒟蒻膜拜无上学神zyk和lyb


(免责声明:如果你提交我的代码而不能通过的话,我不负任何责任;)

(数据截止至2017.4.23 10:00)


1.KPM的简单题

尝试人数 23

通过人数 23

通过率 100%


十分简单的一个高精度题目。(如果你不知道什么是高精度,请自行百度  http://baike.baidu.com/link?url=M-w5KoXet9NoFSXNIoithD0phumxgPeeJiLPbJxe2X1paNi-q95jzj5NQDE55RSJvVkBBVR-HpQnzHC5LuZPYv1FTn6FEvcA8mGgpAct-C279ojqKMt4o2UaRB9lJJdq  )有几点需要注意:

1.认真读题目!认真读题目!!没有仔细看数据范围的我差点开了个unsigned long long!!

2.进位时的处理,这是让很多同学想了很久的地方。

3.数组应该开多大?2^64次方的数据大小,肯定小于10^64,两个数加起来也一定小于10^65,所以开100的数组就够了。

OK,第一题就这样。

(突然发现自己忘了贴代码)

#include<cstdio>
#include<cstring>
using namespace std;
char a1[10005],b1[10005];
int a[10005],b[10005],c[10005],i;
int main()
{
    int t=10;
    while(t--)
    {
        memset(a1,0,sizeof a1);
        memset(b1,0,sizeof b1);
        memset(a,0,sizeof a);
        memset(b,0,sizeof b);
        memset(c,0,sizeof c);
        scanf("%s%s",a1,b1);
        for(int i=0;i<strlen(a1);i++)a[i]=a1[strlen(a1)-i-1]-'0';
        for(int i=0;i<strlen(b1);i++)b[i]=b1[strlen(b1)-i-1]-'0';
        for(int i=0;i<10000;i++)c[i]=a[i]+b[i];
        for(int i=1;i<9999;i++)
        {
            c[i]+=c[i-1]/10;
            c[i-1]%=10;
        }
        for(i=10000;i>=1;i--)if(c[i]!=0)break;
        for(;i>=0;i--)printf("%d",c[i]);
        printf("\n");
    }
    return 0;
}


2.环保轨道1

尝试人数 19

通过人数 19

通过率 100%


这是一道最短路的题目。

首先,注意内存限制:131000kb。这说明可以开一个邻接矩阵(我很不喜欢邻接链表的好不好)。

提示:floyd会超时,但是,如果你真不会dijkstra/SPFA,你可以用它来骗骗分。

(在这里膜拜一下用SPFA的学圣)

有一点需要注意:若不能搭乘轨道到达,就不去宣传,也就是说最后加总的时候,dist数组里大于infinity的不能加(话说那个样例一点用都没有,根本看不出不去宣传时的情况)。

上代码:

#include<iostream>
#include<cstdio>
using namespace std;
const int maxn=1003;
const int inf=1<<29;
int t[maxn][maxn];
int I,J,n,m;
int a=75000;
int main()
{
    for(int i=0;i<maxn;i++)
    for(int j=0;j<maxn;j++)t[i][j]=inf;
    cin>>n>>m;I=1;
    for(int i=0;i<m;i++)
    {
        int x,y,c;
        cin>>x>>y>>c;
        t[x][y]=c;
    }
    int cur, minn=inf,dist[maxn];
    for(int i=0;i<maxn;i++)dist[i]=inf;
    bool tf[maxn];
    for(int i=0;i<maxn;i++)tf[i]=false;
    cur=I;tf[cur]=true;dist[cur]=0;
    do
    {
        for(int i=1;i<maxn;i++)
        if(!tf[i]&&t[cur][i]!=inf&&dist[i]>dist[cur]+t[cur][i])
        dist[i]=dist[cur]+t[cur][i];
        minn=inf;
        for(int i=1;i<maxn;i++)
        if(!tf[i]&&minn>dist[i]){minn=dist[i];cur=i;}
        tf[cur]=true;
    }while(a--);
    double ans=0;
    for(int i=2;i<=n;i++)if(dist[i]<inf)ans+=0.2*dist[i];
    printf("%.1lf\n",ans);
    return 0;
}


3.鸣人和佐助

尝试人数 17

通过人数 6

通过率 35%


这不就是暴力搜索吗?(此人已经被打死)


这是全卷最难的题目(废话),在这里膜一下通过的大神和蒟蒻:大神吴雨桐,大神quzhizhou,大神龙狙,大神Kesdiael Ken(zyk),天天打游戏只会骗分还和csz抢某某某的蒟蒻377isrubbish,大神0721林沛隆(lpl)。


好了,说一下正解思路吧。(请看代码中的注释)

哎,交了三次才过。


## 这是错误的代码!


#include<iostream>
#include<cstring>
#include<queue>
#include<cstdio>
using namespace std;
int dx[4]={1,-1,0,0},dy[4]={0,0,1,-1},T=500000;
bool flag[205][205]={},tf=false;
char a[205][205];
struct node
{
    int mx,my,t,time;
};
int main()
{
    queue<node> q;
    int mx,my,gx,gy,m,n,t,ans=-1;cin>>m>>n>>t;
    memset(a,'.',sizeof a);
    for(int i=1;i<=m;i++)
    {
        getchar();
        for(int j=1;j<=n;j++)cin>>a[i][j];
    }
    for(mx=1;mx<=m;mx++)
    {
        for(my=1;my<=n;my++)if(a[mx][my]=='@')break;
        if(my!=n+1)break;
    }
    for(gx=1;gx<=m;gx++)
    {
        for(gy=1;gy<=n;gy++)if(a[gx][gy]=='+')break;
        if(gy!=n+1)break;
    }
    node first;
    first.mx=mx;first.my=my;
    first.t=t;first.time=0;
    q.push(first);
    while(T--&&!q.empty())
    {
        node last=q.front(),w;
        q.pop();
        flag[last.mx][last.my]=true;
        if(last.mx==gx&&last.my==gy){ans=last.time;break;}
        for(int i=0;i<4;i++)
        {
            if(flag[last.mx+dx[i]][last.my+dy[i]])continue;
            if(a[last.mx+dx[i]][last.my+dy[i]]=='.')continue;
            if(a[last.mx+dx[i]][last.my+dy[i]]=='*'||
            a[last.mx+dx[i]][last.my+dy[i]]=='+'||a[last.mx+dx[i]][last.my+dy[i]]=='@')
            {
                w.mx=last.mx+dx[i];w.my=last.my+dy[i];
                w.t=last.t;w.time=last.time+1;
                q.push(w);
            }
            if(a[last.mx+dx[i]][last.my+dy[i]]=='#')
            {
                if(last.t>0)
                {
                    w.mx=last.mx+dx[i];w.my=last.my+dy[i];
                    w.t=last.t-1;
                    w.time=last.time+1;
                    q.push(w);
                }
                else continue;
            }
        }
        if(tf)break;
    }
    cout<<ans<<endl;
    return 0;
}

当时写的时候犯下了许多错误:

1.一开始结构体里还传了二维数组,卡得要死。

2.那个T是什么?是我用来骗分的。

3.判断重复的数组没有加入查克拉能量,多次重复,导致出错。


正解代码:

//经过无数次的推翻再重写:

#include<cstdio>
#include<queue>//头文件
using namespace std;//命名空间
struct node{int HP,ans,x,y;};//单个节点的定义
queue<node>q;//广度优先搜索需要用到队列
int n,m,t,ox,oy,minx=9999999;//ox,oy是目标状态(佐助的位置)
bool v[201][201][11];//判断是否已经达到过的状态:第一,二维是x,y坐标,第三维是查克拉能量。
char c[201][201];//存储地图
int dx[4]={0,0,-1,1},dy[4]={-1,1,0,0};//变化量(其实当时应该用const的)
int main()
{
    scanf("%d%d%d",&n,&m,&t);//输入
    node a,b,d;//a是最初状态,b是当前状态,d是即将入队的状态

    for(int i=0;i<n;++i)
    {
        scanf("%s",c[i]);//单行字符读入
        for(int j=0;j<m;++j)
        if(c[i][j]=='@')
        {
            a.HP=t;
            a.x=i;
            a.y=j;
            a.ans=0;
            q.push(a);
        }//找到鸣人的位置,更新数据,存储为a节点,推入队列
        else if(c[i][j]=='+')
        {
            ox=i;
            oy=j;
        }//找到佐助的位置,存储为x,y坐标形式
    }
    while(!q.empty())//广度优先搜索算法核心语句
    {
        b=q.front();//取头
        for(int i=0;i<4;++i)//从上,下,左,右四个方向依次判断
        {
            d=b;//d是即将入队的结构体
            d.x+=dx[i];
            d.y+=dy[i];//先行更新x,y坐标
            if(d.x>=0&&d.x<n&&d.y>=0&&d.y<m)//判断是否为边缘
            {
                if(c[d.x][d.y]=='#')d.HP--;//如果为大蛇丸的手下
                if(!v[d.x][d.y][d.HP]&&d.HP>=0)//如果没有到达过此状态并且还有查克拉
                {
                    d.ans++;//时间增加
                    v[d.x][d.y][d.HP]=true;//标记为已经到达过
                    q.push(d);//入队
                    if(d.x==ox&&d.y==oy)
                    {
                        printf("%d\n",d.ans);
                        return 0;
                    }//判断是否到达了目标状态,如果是,输出答案,程序结束
                }
            }
        }
        q.pop();//上下左右均判断入队,弹出首个元素
    }//在队列非空时继续执行
    printf("-1\n");//如果没有找到目标状态,输出-1
    return 0;//必须要加的一行
}//程序结束

改进了的部分在于:

1.刚才提到过的几点

2.判断是否在边缘,减少了在外面包围一圈其他字符的麻烦。



总结:

    由这次考试可以看出:

    要提高知识“水”平,要提高对信息之美的认识(语出lyb)(划掉划掉)

    要积攒人品啊。

1 0
原创粉丝点击