Codeforces 1351C - Skier
测试场,分数取决于手速……
题面
题意
一个人从某个点开始,按照给定的 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;
}