1 条题解
-
0
思路
题意简述:多组数据,每组给出一串
1~9组成的数字,判断它是否是合法的安卓图案解锁轨迹。规则有两条:- 每个点最多使用一次;
- 从点 滑到点 时,如果两点连线的中点恰好是九宫格中的另一个点 (三点共线且 是线段中点),那么 必须在此前已经被使用过,否则这一步非法。
做法就是直接模拟:
- 先把编号 映射到九宫格坐标:编号 对应行 、列 。
- 用
vis[1..9]记录每个点是否已经走过,并把第一个点标记为已用。 - 依次检查相邻的两个点 :
- 若 已经走过,违反“每个点最多一次”,输出
NO; - 判断中点是否为格点:当且仅当两点的行坐标之和与列坐标之和都为偶数时,平均值才是整数,即中点落在九宫格内。此时算出中点编号,若它尚未被使用,则这一步跨过了未使用的点,输出
NO; - 通过检查后,把 标记为已使用。
- 若 已经走过,违反“每个点最多一次”,输出
- 全部相邻步都合法则输出
YES。
正确性:模拟逐条覆盖了两条规则。重复使用点会在
vis[a[i]]处被抓到;只有两坐标和均为偶数时才存在整数中点,而 范围内两个格点的平均仍在九宫格内,所以此时“中点编号未使用就该判非法”与规则完全一致;其它情况(如斜向相邻、行或列差为奇数等)没有中间格点,不构成“跨点”,允许直接连接。复杂度:每组数据只扫描一遍字符串,时间 ,其中 为密码长度;空间 (坐标表、访问数组大小固定为 10)。由于只有 9 个点,长度超过 9 的串必然重复,会被判为
NO。代码
#include<bits/stdc++.h> #define int long long #define dd double #define str string #define el cout << endl #define re return #define ff first #define ss second #define pll pair<int,int> #define pdd pair<dd,dd> #define all(x) x.begin(),x.end() #define pb push_back #define sz(x) (int) x.size() using namespace std; // 判断一串数字是否为合法的安卓图案解锁轨迹 void go(str s){ vector<int>a; // vis[v] 表示编号 v 的点是否已经被使用 vector<int>vis(10,0); // coor[v] 保存编号 v 在 3x3 九宫格中的坐标 vector<pll>coor(10,{0,0}); for(int i=1;i<=3;i++){ for(int j=1;j<=3;j++){ coor[(i-1)*3+j] = {i,j}; } } // 把字符密码转换成数字序列 for(char i:s){a.pb(i-'0');} // 第一个点直接标记为已使用 vis[a[0]] = 1; for(int i=1;i<a.size();i++){ int lx = coor[a[i-1]].ff, ly = coor[a[i-1]].ss; int nx = coor[a[i]].ff, ny = coor[a[i]].ss; // 目标点之前已经走过,违反“每个点最多使用一次” if(vis[a[i]]){ cout<<"NO";el;re; } // 行列坐标和都为偶数时,中点才是九宫格内的整数格点 if((lx+nx)%2==0 and (ly+ny)%2==0){ int mx = (lx+nx)/2; int my = (ly+ny)/2; int num = (mx-1)*3 + my; // 跨过的中点必须已经被使用 if(!vis[num]){ cout<<"NO";el;re; } } vis[a[i]] = 1; } // 所有相邻步都合法 cout<<"YES";el; } signed main() { ios::sync_with_stdio(false); cin.tie(nullptr);cout.tie(nullptr); int t=1; // 本题为多组数据,一直读到文件结束,不需要预先读取组数 str s; while(cin>>s){ go(s); } return 0; }
- 1
信息
- ID
- 53
- 时间
- 1000ms
- 内存
- 256MiB
- 难度
- 4
- 标签
- 递交数
- 0
- 已通过
- 0
- 上传者