把相邻两段边的转向累计起来,总转角为正则逆时针,为负则顺时针。
OJ: usaco
题目 ID: 1109
难度:普及-
标签:几何模拟字符串
日期: 2026-07-11 13:35
题意
给定若干条由
判断按字符串顺序沿着栅栏走时,围住的区域在右侧还是左侧;右侧输出 CW,左侧输出 CCW。
思路
用有向面积校验
一个常见做法是按路径走出坐标点,再用多边形有向面积判断方向:
cpp
/**
* Author by Rainboy blog: https://rainboylv.com github: https://github.com/rainboylvx
* rbook: -> https://rbook.roj.ac.cn https://rbook2.roj.ac.cn
* rainboy的学习导航网站: https://idx.roj.ac.cn
* create_at: 2026-07-11 13:35
* update_at: 2026-07-11 13:39
*/
// brute.cpp:小数据校验解,用坐标和有向面积判断方向。
#include <bits/stdc++.h>
using namespace std;
void move_one(char ch, int &x, int &y) {
if (ch == 'N') y++;
if (ch == 'S') y--;
if (ch == 'E') x++;
if (ch == 'W') x--;
}
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int n;
cin >> n;
for (int tc = 1; tc <= n; tc++) {
string s;
cin >> s;
int x = 0;
int y = 0;
long long area2 = 0; // 多边形有向面积的 2 倍。
for (int i = 0; i < (int)s.size(); i++) {
int nx = x;
int ny = y;
move_one(s[i], nx, ny);
area2 += 1ll * x * ny - 1ll * nx * y;
x = nx;
y = ny;
}
if (area2 > 0) {
cout << "CCW\n";
} else {
cout << "CW\n";
}
}
return 0;
}在通常坐标系下,有向面积为正表示逆时针,为负表示顺时针。
累计转角
官方解析的思路是:顺时针路径整体更倾向于右转,逆时针路径整体更倾向于左转。
把方向编号为:
text
E = 0, N = 1, W = 2, S = 3相邻两段边形成一个转角:
- 左转贡献
+1; - 右转贡献
-1; - 直行贡献
0。
沿简单闭合曲线走一圈,如果整体是逆时针,总转角为
因此只需要比较每一对相邻方向:
text
s[i] -> s[(i + 1) % len]最后如果 total_turn > 0,输出 CCW;否则输出 CW。
以 NESW 为例:
text
N -> E 右转
E -> S 右转
S -> W 右转
W -> N 右转总转角为负,所以是 CW。
代码
cpp
/**
* Author by Rainboy blog: https://rainboylv.com github: https://github.com/rainboylvx
* rbook: -> https://rbook.roj.ac.cn https://rbook2.roj.ac.cn
* rainboy的学习导航网站: https://idx.roj.ac.cn
* create_at: 2026-07-11 13:35
* update_at: 2026-07-11 13:39
*/
#include <bits/stdc++.h>
using namespace std;
int direction_id(char ch) {
if (ch == 'E') return 0;
if (ch == 'N') return 1;
if (ch == 'W') return 2;
return 3; // S
}
int turn_value(char from, char to) {
int a = direction_id(from);
int b = direction_id(to);
int diff = (b - a + 4) % 4;
if (diff == 1) return 1; // 左转 90 度。
if (diff == 3) return -1; // 右转 90 度。
return 0; // 直行。
}
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int n;
cin >> n;
for (int tc = 1; tc <= n; tc++) {
string s;
cin >> s;
int total_turn = 0;
int len = (int)s.size();
for (int i = 0; i < len; i++) {
total_turn += turn_value(s[i], s[(i + 1) % len]);
}
if (total_turn > 0) {
cout << "CCW\n";
} else {
cout << "CW\n";
}
}
return 0;
}复杂度
每条路径扫描一遍,时间复杂度为
只使用常数个变量,额外空间复杂度为
总结
这题的关键是把“顺时针/逆时针”转化成局部转向的总和。
只要路径是简单闭合曲线,绕一圈后的总转角正负就能唯一确定方向。