• Codeforces 1351C



    测试场,分数取决于手速……


    题面

    Prob




    题意

    一个人从某个点开始,按照给定的 NSWE 顺序分别向 北南西东 四个方向移动,每次移动距离为 1

    如果某条线段没有被走过,那么就需要花 5 秒时间

    如果已经走过,则只需要花 1 秒时间

    问走完全程花了多久




    解题思路

    其实只要为每条线段记录下是否访问过,直接按顺序模拟即可

    方法有很多种,但都是化线为点,用map来存点判断是否访问过某条线段的

    下面三个程序,键值个数分别为 2/4/3

    (定义N为y++,S为y--,W为x--,E为x++,当作平面直角坐标系看,上北下南左西右东)




    程序 1

    因为可以走的线段构成了坐标系的网格

    可以化线段为点,再用map存点即可

    网格的每条线段除了两端点以外的任何点都可以单独代表这条线段

    所以我们可以取线段的中点来作为map的键值

    (46ms/1000ms 8600KB)

    #include<bits/stdc++.h>
    using namespace std;
    typedef pair<double,double> P;
    
    void solve()
    {
        string str;
        map<P,bool> mp;
        double x=0,y=0;
        int ans=0;
        cin>>str;
        for(char c:str)
        {
            P pd;
            if(c=='N')
                pd=P(x,y+0.5),y+=1.0;//往北走,现状态为(x,y),下一状态为(x,y+1),中点为(x,y+0.5),下同
            else if(c=='S')
                pd=P(x,y-0.5),y-=1.0;
            else if(c=='W')
                pd=P(x-0.5,y),x-=1.0;
            else
                pd=P(x+0.5,y),x+=1.0;
            if(mp[pd])
                ans++; //访问过,答案直接+1
            else
            {
                ans+=5;
                mp[pd]=true; //未访问过进行标记
            }
        }
        cout<<ans<<'
    ';
    }
    int main()
    {
        ios::sync_with_stdio(0);
        cin.tie(0);cout.tie(0);
        int T;cin>>T;
        while(T--)
            solve();
        return 0;
    }
    



    程序 2

    双重pair,将每条线段的两端点共四个值作为map的键值来模拟

    (62ms/1000ms 13400KB)

    #include<bits/stdc++.h>
    using namespace std;
    typedef pair<int,int> P;
    typedef pair<P,P> PP;
    
    void solve()
    {
        string str;
        map<PP,bool> mp;
        int x=0,y=0,ans=0;
        cin>>str;
        for(char c:str)
        {
            P p1=P(x,y),p2;
            if(c=='N')
                p2=P(x,++y);
            else if(c=='S')
                p2=P(x,--y);
            else if(c=='W')
                p2=P(--x,y);
            else
                p2=P(++x,y);
            if(mp[PP(p1,p2)])
                ans++;
            else
            {
                ans+=5;
                mp[PP(p1,p2)]=mp[PP(p2,p1)]=true; //标记时需要双向标记
            }
        }
        cout<<ans<<'
    ';
    }
    int main()
    {
        ios::sync_with_stdio(0);
        cin.tie(0);cout.tie(0);
        int T;cin>>T;
        while(T--)
            solve();
        return 0;
    }
    



    程序 3

    以某条线段的左/下顶点作为基础顶点,再引入一个值dir代表朝向,三个值作为键值

    前面都是用pair,这里就重写一个结构体好了(当时也是这么写的……)

    注意把结构体放入map作为键值时需要重载运算符

    (46ms/1000ms 7800KB)

    #include<bits/stdc++.h>
    using namespace std;
    
    struct node
    {
        int x,y,dir;
        bool operator < (const node& a) const
        {
            if(x!=a.x)return x<a.x;
            if(y!=a.y)return y<a.y;
            return dir<a.dir;
        } //本题对顺序无要求,只要能够让map根据大小关系构造出树即可
    };
    
    void solve()
    {
        string str;
        map<node,bool> mp;
        int x=0,y=0,ans=0;
        cin>>str;
        for(char c:str)
        {
            node nd;
            if(c=='N')
                nd=node{x,y++,1}; //向上走,取下端点(走前),方向为竖
            else if(c=='S')
                nd=node{x,--y,1}; //向下走,取下端点(走后),方向为竖
            else if(c=='W')
                nd=node{--x,y,2}; //向左走,取左端点(走后),方向为横
            else
                nd=node{x++,y,2}; //向右走,取左端点(走前),方向为横
            if(mp[nd])
                ans++;
            else
            {
                ans+=5;
                mp[nd]=true;
            }
        }
        cout<<ans<<'
    ';
    }
    int main()
    {
        ios::sync_with_stdio(0);
        cin.tie(0);cout.tie(0);
        int T;cin>>T;
        while(T--)
            solve();
        return 0;
    }
    

  • 相关阅读:
    C# 获取文件的修改时间、访问时间、创建时间
    Nhibernate Or多条件查询
    C# 将GridView当前页数据导成Execl
    C# 清空文件夹
    TreeView默认收缩
    JS控制控件的隐藏显示
    div置顶,不随滚动条滚动而滚动
    js 父窗体与子窗体的调用
    树形菜单的绑定以及链接
    2010.10.16 OA项目组一周报告 CQ
  • 原文地址:https://www.cnblogs.com/stelayuri/p/12846895.html
Copyright © 2020-2023  润新知