Codeforces 1351C - Skier


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


题面

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<<'\n';
}
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<<'\n';
}
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<<'\n';
}
int main()
{
    ios::sync_with_stdio(0);
    cin.tie(0);cout.tie(0);
    int T;cin>>T;
    while(T--)
        solve();
    return 0;
}

posted @ 2020-05-08 00:27  StelaYuri  阅读(392)  评论(0编辑  收藏  举报