2017计蒜之道程序设计大赛初赛第四场题解
来源:互联网 发布:json字符串转化成数组 编辑:程序博客网 时间:2024/05/21 09:23
比赛链接
题目可以在比赛的题目列表中查看
商汤科技的安全令牌
商汤科技的安全令牌
商汤科技致力于引领人工智能核心“深度学习”技术突破,构建人工智能、大数据分析行业解决方案。作为一家人工智能公司,用机器自动地解决各类实际问题自然不在话下。近日,商汤科技推出了一套安全令牌,令牌如下图所示:
安全令牌上的小孔有 nn 行 mm 列,不过有些行和有些列已经用导线整体焊接了,共有 kk 根导线。
我们可以在安全令牌上 不重叠 地焊接若干个小芯片,每个芯片需要在相邻(不能斜着相邻,必须平行于行或列)的两个没有被焊接的小孔上固定。不能固定在已经被整体焊接的行或列上。
安全令牌上最多可以放置多少个芯片,就代表了这个安全令牌对应的校验码。当然,由于安全令牌上小孔的密度会很大,是很难目测出对应的校验码的。你作为商汤科技的实习生,需要写出一个程序,能够自动地算出一个给定的安全令牌的校验码。
输入格式
输入第一行三个整数 n,m(1 \le n,m \le 100)n,m(1≤n,m≤100),k(0 \le k \le n + m)k(0≤k≤n+m)。
接下来输入 kk 行,每行输入两个整数 d(0≤d≤1),c。如果 d=0,表示第 c(1≤c≤n) 行被整体焊接了,如果 d=1,表示第 c(1≤c≤m) 列被整体焊接了。
输出格式
输出安全令牌对应的校验码。
样例输入
4 5 2
0 3
1 4
样例输出
5
网上看到一个dfs的思路:
题目大意:给出一个图,一些点不能访问,在每个连通块中,两相邻的点可以配对,问最多有几对?
解题思路: dfs
#include<iostream>#include<cstring>#include<cmath>#include<ctime>#include<cstdlib>#include<algorithm>#include<iomanip>#include<fstream>#include<map>using namespace std;const int MAXN=1e6+10;const int INF=0x3f3f3f3f;int G[105][105];bool vis[105][105];int dx[4]={0,0,1,-1};int dy[4]={1,-1,0,0};int n,m,kk;bool ok(int i,int j){ if(i<1||i>n||j<1||j>m) return false; return true;}int dfs(int i,int j){ vis[i][j]=true; int res=1; for(int k=0;k<4;k++) { int ti=i+dx[k]; int tj=j+dy[k]; if(G[ti][tj]==0) continue; if(ok(ti,tj)&&!vis[ti][tj]) { res+=dfs(ti,tj); } } return res;}int main(){ //freopen("in.txt","r",stdin); //freopen("out.txt","w",stdout); while(cin>>n>>m>>kk) { int op,rc; memset(vis,false,sizeof(vis)); for(int i=1;i<=n;i++) { for(int j=1;j<=m;j++) { G[i][j]=1; } } for(int i=1;i<=kk;i++) { cin>>op>>rc; if(op==0) { for(int j=1;j<=m;j++) G[rc][j]=0; }else { for(int i=1;i<=n;i++) G[i][rc]=0; } } int cc=0; int ans=0; for(int i=1;i<=n;i++) { for(int j=1;j<=m;j++) { if(G[i][j]==0) continue; else { cc=dfs(i,j); ans+=(cc/2); } } } cout<<ans<<endl; } return 0;}
命题人:镇高红
安全令牌分割成为若干个独立的矩形区域。一个矩形区域如果长和宽都是奇数,那么就会多出一个小孔,否则每个小孔都能用上。
商汤科技的行人检测
命题人:商静波
本题给定 n 对变换前后的二维点,要求在有一定容错(错误的点对数严格不超过一半)的情况下,对变换进行复原。其关键条件在于对容错率的限制:错误的点对数严格不超过一半。
商汤科技的行人检测(简单)
商汤科技近日推出的 SenseVideo 能够对视频监控中的对象进行识别与分析,包括行人检测等。在行人检测问题中,最重要的就是对行人移动的检测。由于往往是在视频监控数据中检测行人,我们将图像上的行人抽象为二维平面上若干个的点。那么,行人的移动就相当于二维平面上的变换。
在这道题中,我们将行人的移动过程抽象为 平移,有两个 移动参数:dx 和 dy。每次行人的移动过程会将行人对应的所有点全部平移,对于平移前的点 (x,y),平移后的坐标为 (x+dx,y+dy)。
我们现在已知一个行人对应着 n 个点,坐标分别为 (x1,y1),(x2,y2)…(xn,yn),平移后的坐标分别为 (x1′,y1′),(x2′,y2′)…(xn′,yn′)。
很显然,通过平移前后的正确坐标,很容易算出行人的移动参数,但问题没有这么简单。由于行人实际的移动并不会完全按照我们预想的方式进行,因此,会有一部分平移后的坐标结果不正确,但可以确保 结果不正确的坐标数量严格不超过一半。
你现在作为商汤科技的实习生,接手了这个有趣的挑战:算出行人的移动参数。如果不存在一组合法的移动参数,则随意输出一组参数;如果有多种合法的移动参数,输出其中任意一组合法的即可。
输入格式
第一行输入一个整数 n(1≤n≤105),表示行人抽象出的点数。
接下来 n 行,每行 4 个 整数。前两个数表示平移前的坐标,后两个数表示平移后的坐标。
坐标范围在 −109 到 109 之间。
输出格式
一行两个整数,dx 和 dy,表示行人的移动参数。
样例输入
50 0 1 10 1 1 21 0 2 11 1 0 02 1 1 0
样例输出
1 1
商汤科技的行人检测(简单)
商汤科技近日推出的 SenseVideo 能够对视频监控中的对象进行识别与分析,包括行人检测等。在行人检测问题中,最重要的就是对行人移动的检测。由于往往是在视频监控数据中检测行人,我们将图像上的行人抽象为二维平面上若干个的点。那么,行人的移动就相当于二维平面上的变换。
在这道题中,我们将行人的移动过程抽象为 平移,有两个 移动参数:dx 和 dy。每次行人的移动过程会将行人对应的所有点全部平移,对于平移前的点 (x,y),平移后的坐标为 (x+dx,y+dy)。
我们现在已知一个行人对应着 n 个点,坐标分别为 (x1,y1),(x2,y2)…(xn,yn),平移后的坐标分别为 (x1′,y1′),(x2′,y2′)…(xn′,yn′)。
很显然,通过平移前后的正确坐标,很容易算出行人的移动参数,但问题没有这么简单。由于行人实际的移动并不会完全按照我们预想的方式进行,因此,会有一部分平移后的坐标结果不正确,但可以确保 结果不正确的坐标数量严格不超过一半。
你现在作为商汤科技的实习生,接手了这个有趣的挑战:算出行人的移动参数。如果不存在一组合法的移动参数,则随意输出一组参数;如果有多种合法的移动参数,输出其中任意一组合法的即可。
输入格式
第一行输入一个整数 n(1≤n≤105),表示行人抽象出的点数。
接下来 n 行,每行 4 个 整数。前两个数表示平移前的坐标,后两个数表示平移后的坐标。
坐标范围在 −109 到 109 之间。
输出格式
一行两个整数,dx 和 dy,表示行人的移动参数。
样例输入
50 0 1 10 1 1 21 0 2 11 1 0 02 1 1 0
样例输出
1 1
解题思路:x,y坐标偏移,丢到unordered_map(或者map)里,然后按值排序,取最大的,如果大于等于一半就可以。
#include<iostream> #include<cstring> #include<cmath> #include<ctime> #include<unordered_map> #include<cstdlib> #include<algorithm> #include<iomanip> #include<fstream> #include<set> #include<vector> #include<map> using namespace std; const int MAXN=1e5+10; const int INF=0x3f3f3f3f; typedef long long LL; unordered_map<LL,LL> mx; unordered_map<LL,LL> my; struct node { LL d,c; node(LL _d,LL _c):d(_d),c(_c){} }; vector<node> vx,vy; bool cmp(node a,node b) { return a.c>b.c; } int main() { int n; int x1,y1,x2,y2; while(cin>>n) { mx.clear(); my.clear(); vx.clear(); vy.clear(); for(int i=1;i<=n;i++) { cin>>x1>>y1>>x2>>y2; mx[x2-x1]++; my[y2-y1]++; } unordered_map<LL,LL>::iterator it; for(it=mx.begin();it!=mx.end();it++) vx.push_back(node(it->first,it->second)); sort(vx.begin(),vx.end(),cmp); vector<node>::iterator itv; itv=vx.begin(); LL ansx=0,ansy=0; if((*itv).c>=n/2) { ansx=(*itv).d; for(it=my.begin();it!=my.end();it++) vy.push_back(node(it->first,it->second)); sort(vy.begin(),vy.end(),cmp); itv=vy.begin(); if((*itv).c>=n/2) { ansy=(*itv).d; cout<<ansx<<" "<<ansy<<endl; }else { cout<<ansx<<" "<<ansy<<endl; } }else { cout<<ansx<<" "<<ansy<<endl; } } return 0; }
简单版本
在简单版本中,由于只有平移,我们可以首先计算出每对点对应的平移量。由于错误的点对数严格不超过一半,我们可以直接统计 n 组平移量中的众数,即可得到答案。
本题还可以通过限制内存,要求大家在常数内存下完成。只需要一个计数器和一个与计数器对应的平移量即可。每次读入一个点对,计算新的平移量。
(1)若此时计数器为 0,则存下这个平移量,计数器修改为 1;
(2)若此时计数器不为 0,则检查是否与存着的平移量相同:如果相同,则计数器加一;否则减一。最终幸存下来的平移量即为答案。
中等版本
在中等版本中,除了平移之外,还加入了旋转和拉伸。可以发现只需要枚举哪两对点是正确变换的,就可以计算出对应的拉伸、旋转、平移的量,从而验证是否有严格超过一半的点对满足这组变换。时间复杂度 O(n3)。注意特判只有一个点对的情况。
困难版本
在困难版本中,点对数 n 从 100 升级到了 100000。其算法本质并没有发生改变,依然是枚举两对点,然后验证。但是其枚举顺序,必须从按顺序枚举,改为随机枚举,以避免最坏复杂度。注意到错误的点对数严格不超过一半,因此我们有超过 1/4 的概率,枚举到的两对点就是正确的。对应的,枚举一次失败的概率就不足 3/4。这意味着:随机枚举 10 次,失败的概率不足 5.6%;随机枚举 20 次,失败的概率不足 0.3%;随机枚举 50 次,失败的概率不足 0.00005%。所以,只需要常数次枚举,基本可以保证找到答案。时间复杂度 O(n)。
补充一个别处看来的思路(没有代码,无从知晓正确性)
只是记录一下:
首先先n^2或随机枚举出一对点
根据抽屉原理可得枚举(n/2)^2+1次后至少有一对点全是对的
然后对于两个对的点,首先考虑缩放比例
不论是旋转还是平移两个点之间的距离都不会改变
而缩放对两点间的距离改变的倍数就等于缩放的倍数
(因为相似三角形
所以缩放就求出来了
然后可以发现缩放和旋转其实可以反过来
那么把缩放放到前面,现在考虑中间只有旋转和平移
对于旋转
因为平移不会改变两个点之间连线的斜率,所以直接根据斜率的变化可以求出旋转角
然后结合旋转角和缩放比就可以直接把平移偏移量求出来了
此题完结
- 2017计蒜之道程序设计大赛初赛第四场题解
- 2017计蒜之道程序设计大赛初赛第一场题解
- 2017计蒜之道程序设计大赛初赛第二场题解
- 2017计蒜之道程序设计大赛初赛第三场题解
- 2017计蒜之道程序设计大赛初赛第五场题解
- 2017计蒜之道程序设计大赛初赛第六场题解
- 2017计蒜之道程序设计大赛初赛第五场
- 2017计蒜之道程序设计大赛初赛第五场
- 2017计蒜之道初赛第四场AB两题题解
- 2017 计蒜之道初赛第五场题解
- 2017 计蒜之道初赛第六场 题解
- 2017 计蒜之道 初赛 第四场
- 2017 计蒜之道 初赛 第四场
- 2017计蒜之道程序设计大赛复赛题解
- 计蒜之道 初赛 第二场 题解 树形dp
- 2017计蒜之道初赛第四场-商汤科技的安全令牌
- 2017计蒜之道初赛第四场-商汤科技的行人检测(简单)
- 2017 计蒜之道 初赛 第四场 (计蒜课比赛)第一题
- test adasfadf
- 跨数据库查询(跨DB查询)并嵌套插入数据
- android自学第六天 Activity管理及Intent七大属性
- 激光雷达学习笔记(三)特征提取
- jquary简单日历签到效果实现
- 2017计蒜之道程序设计大赛初赛第四场题解
- C++中文件读取处理(按行或者单词)
- java冒泡排序
- C++ 二级指针
- 谢谢关注,烦请移步至我的个人站点www.samyoc.com
- Meteor changePassword
- 关于vue.js安装那点事
- ss-libev 源码解析local篇(2):ss_local和socks5客户端握手
- ORA-12638: 身份证明检索失败