# 【精选】有趣的尝试,洛谷P6159光图(让算法动一动)
视频展示
程序展示
程序制作
题目介绍(题目来源于洛谷)以下是洛谷P6159光图
[Cnoi2020]光图
题目背景
简洁中蕴含着伟大。
Cirno 不经意地把一个内部完全反射的圆分成了 $12$ 等分,等分点分别记作 $A_0$, $A_1$, $A_2$, $\cdots$ , $A_{11}$。
随后,她不经意地将一束光从一点发出,朝向另一点,重复,反射,迭代,便得到了一幅美妙的光图。
这一切都发生在不经意之间。
她不经意地发现了这一幕,并且不经意地记下了这个不经意的结论,又在某一刻不经意地回忆起。
幻想乡的每一天一切都是这么不以为意,多好的一天啊!
题目描述
Rumia 有一个单位圆,被分成 $n$ 等分,等分点分别记作 $A_0$, $A_1$, $A_2$, $\cdots$ , $A_{n-1}$。
现在她从 $A_0$ 向 $A_p$ 发射一束光,经过 $k$ 次反射,到达了 $A_t$。
Rumia 想知道 $t$ 的值,由于 Cirno 并不想帮她,所以 Rumia 转而求助于你。
输入格式
一行,三个整数,$n,p,k$。
输出格式
一行,一个整数 $t$。
样例 #1
样例输入 #1
12 5 2
样例输出 #1
10
样例 #2
样例输入 #2
1000 342 3472844
样例输出 #2
648
提示
Sample1 解释
后置物理知识
- 连续曲线反射规律 : 入射光线与出射光线关于入射点在曲线上切线夹角相等。
数据范围约定
「本题采用捆绑测试」
- Subtask1( $80\%$ ) : $n, k \le 10^6$
- Subtask2( $20\%$ ) : $n, k \le 10^9$
对于 $100\%$ 的数据 : $0 < p < n \le 10^9$, $0 < k \le 10^9$。
后记
- Cirno 得到的光图就是传说中的十二芒星图。
一、项目环境
1.Visual Studio 2022
2.安装easyx图形库,可以调用头文件
include<easyx.h>
简单介绍一下easyx图形库
EasyX库是一个基于C语言的图形界面库,可以用于Windows操作系统下的图形界面应用程序开发。该库提供了一些易于使用的图形绘制函数和简单的事件处理功能,可以帮助开发者快速地创建各种图形应用程序,如游戏、图形编辑器等。
EasyX库提供了丰富的绘图功能,如直线、矩形、圆形、椭圆、多边形等基本形状的绘制,同时还支持图片、文字、音频等多种媒体资源的加载和处理。此外,EasyX库还支持鼠标、键盘等多种事件的处理,可以让用户与应用程序进行交互。
EasyX库的另一个特点是易于学习和使用。它提供了简单的API,使得初学者也可以轻松地入门,并且具有丰富的在线文档和示例程序,帮助开发者快速地学习和理解如何使用这个库。除此之外,EasyX库还可以和Visual Studio等常见的集成开发环境进行配合使用,使得开发工作更加高效。
总之,EasyX库是一款简单易用、功能强大的图形界面库,适用于初学者和有一定编程基础的开发者,可以用于快速开发各种图形应用程序。
Easyx图形库
二、项目介绍
通过算法,结合easyx库本章将洛谷光图这道题进行了算法可视化,可以更加清晰的看出光在算法的加持下是如何反射的。
三、运行效果展示
测试页面
输入样例1:
24
5 2
效果如下图所示:
四、项目源代码分享
#include<stdio.h>
#include<iostream>
#include<easyx.h>
#include<math.h>
#include<graphics.h>
#include <stdlib.h>
#include <string.h>
#include<iostream>
using namespace std;
/*
输入12的倍数尽量小一点,大了就是一个圆形看不出什么
输入
24
5 2
*/
using namespace std;
#define maxx 100001
#define PI 3.14159265358979323846264338
struct spot {//声明一个点类
long double x;//点的横坐标
COLORREF color;
long double y;//点的纵坐标
}s;
struct stop1 {
spot data[maxx];
}poin;
//打印,连线
void Connection(int n,int p,int k)//被分成n份,从0点到p点,反射k次
{
for (int i = 2; i <= n; i++)
{
int t1 = k * p % n;//反射k次的最后所在点
int t2 = (k-1) * p % n;//反射k-1次的最后所在点
setlinecolor(RED);
line(poin.data[t1].x, poin.data[t1].y, poin.data[t2].x, poin.data[t2].y);
}
}
int main()
{
initgraph(1000, 800, EW_SHOWCONSOLE);
setbkcolor(WHITE);
cleardevice();
setlinecolor(BLACK);
setlinestyle(PS_SOLID,6);
setfillcolor(BLACK);
circle(500, 400, 300);
int i;
int n, p, k;
cin >> n ;
int r = 300;
int oneAngle = 360 / n;// N等分后每个角度的度数
int centerX = 500; // 圆心坐标--X
int centerY = 400;// 圆心坐标--Y
int radius = 300;// 半径
for (int i = 0; i < maxx; i++) {
int tmp = i * oneAngle;
poin.data[i].x = (centerX + radius * cos(tmp * PI / 180));
poin.data[i].y = (centerY + radius * sin(tmp * PI/ 180));
setfillcolor(RED);
solidcircle(poin.data[i].x, poin.data[i].y, 3);
//cout << poin.data[i].x << " " << poin.data[i].y << endl;
//cout << i << "**************************" << endl;
}
cin >> p >> k;
int t1, t2;
int ok;
while (1)
{
k++;
for (int i = 2; i <= n; i++)
{
t1 = k * p % n;//反射k次的最后所在点
t2 = (k - 1) * p % n;//反射k-1次的最后所在点
poin.data[i].color = HSVtoRGB((float)(rand() % 360), 0.8f, 0.9f);
setlinecolor(poin.data[i].color);
line(poin.data[t1].x, poin.data[t1].y, poin.data[t2].x, poin.data[t2].y);
printf("poin.data[%d].x=%lf poin.data[%d].y=%lf\n", t1, poin.data[t1].x, t1, poin.data[t1].y);
printf("poin.data[%d].x=%lf poin.data[%d].y=%lf\n", t2, poin.data[t2].x, t2, poin.data[t2].y);
printf("/**---------------------------------------**/\n");
//Sleep(1);
}
if (k-2 == n)
{
//cin >> ok;
//cin >> p >> k;
p++;
k = 5;
}
}
getchar();
closegraph();
return 0;
}
注意:
这里要提前在Visual Studio中修改一些设置,否则代码将无法顺利运行
修改方法如下:
Step1:在项目中点击鼠标右键,点击属性
Step2:选中高级,点击字符集,点击修改成未设置,点击确定
修改完成
五、总结与反思
本文是博主在寒假期间写洛谷题时的突然有感,算法题总是让人感到枯燥无味,但经过博主这样的修改是不是觉得枯燥无味的算法也增加了一丝丝的色彩,有没有让各位猿子们对算法的热情增加一丝丝呢🤭
番外(如果单纯为了看本题的题解可以看以下内容)
浅浅写一下当时在洛谷提交这道题的算法
提交结果