原题:
## 题目背景
小红、小明和小张去看电影
小明今天看了流浪地球,小张今天看了西红柿首富
那小红该看哪一部电影呢?
## 题目描述
输入三行数字,每行两个数字,分别为小红、小明和小张对科幻片和喜剧片的喜爱程度
分别用余弦相似度和距离公式计算出该给小红推荐哪一部电影,分两行输出
## 输入格式
三行数字,一行两个,表示每个人对科幻片以及喜剧片的喜爱程度
## 输出格式
两行整型,表示该给小红推荐哪一部电影,分别用余弦相似度和距离公式计算
1表示流浪地球,0表示西红柿首富
## 样例 #1
### 样例输入 #1
```
4 5
10 10
9 9
```
### 样例输出 #1
```
0
0
```
## 提示
## 余弦相似度
公式: $cos(\theta) = \frac{x_1x_2+y_1y_2}{\sqrt{x_1^2+y_1^2} \times {\sqrt{x_2^2+y_2^2}}}$
![余弦相似度示意图](https://www.luogu.com.cn/fe/api/problem/downloadAttachment/9x1ep0gq)
$x_1 y_1$表示第一个坐标的x和y坐标
$x_2 y_2$表示第二个坐标的x和y坐标
结果越接近1,两个坐标越相近
## 距离公式
公式: $\sqrt{(x_1-x_2)^2+(y_1-y_2)^2}$
同理
$x_1 y_1$表示第一个坐标的x和y坐标
$x_2 y_2$表示第二个坐标的x和y坐标
结果越小,两个坐标越相近
题解:
# 公式解析
## 余弦相似度
原题公式是: $cos(\theta) = \frac{x_1x_2+y_1y_2}{\sqrt{x_1^2+y_1^2} \times {\sqrt{x_2^2+y_2^2}}}$
$x_1x_2+y_1y_2$ 用`C++`形式表示为 `x1*x2+y1*y2`
$\sqrt{x_1^2+y_1^2} \times {\sqrt{x_2^2+y_2^2}}$ 用`C++`形式表示为 `sqrt(x1 * x1 + y1 * y1) * sqrt(x2 * x2 + y2 * y2)`
所以整个代码可以用如下函数表示:
```cpp
#include<iostream>
#include<cmath>
using namespace std;
double yuxian(int x1, int y1, int x2, int y2){
double result;
result = (x1*x2+y1*y2) / (sqrt(x1 * x1 + y1 * y1) * sqrt(x2 * x2 + y2 * y2));
return result;
}
```
## 距离公式
距离公式如下:
$ \sqrt{(x_1 - x_2)^2 + (y_1 - y_2)^2} $
用`C++`表示就是`sqrt(pow(x1-x2, 2) + pow(y1-y2, 2)`
所以完整函数如下:
```cpp
#include<iostream>
#include<cmath>
using namespace std;
double juli(int x1, int y1, int x2, int y2){
double result;
result = sqrt(pow(x1-x2, 2) + pow(y1-y2, 2));
return result;
}
```
## 完整代码
题目中要求使用此类公式进行相似度比较,小红与谁的电影偏好越相近,就给小红推荐电影
所以我们可以使用以下代码比较
```cpp
int *bijiao(int x1,int y1, int x2, int y2, int x3, int y3){
double result1, result2, result3, result4;
result1 = yuxian(x1, y1, x2, y2);//小红与小明相似度
result2 = juli(x1, y1, x2, y2);
result3 = yuxian(x1, y1, x3, y3); // 小红与小张相似度
result4 = juli(x1, y1, x3, y3);
int *returnvalue = new int;
if (result1 > result3){
returnvalue[0] = 1; // 推荐流浪地球
} else returnvalue[0] = 0; // 推荐西红柿首富
if (result2 < result4){
returnvalue[1] = 1; // 推荐流浪地球
} else returnvalue[1] = 0; // 推荐西红柿首富
return returnvalue;
}
```
值得注意的是,余弦相似度**越接近1越相近**,距离公式**越小越相近**
有了这么多函数,我们可以写主函数了
完整代码:
```cpp
#include<iostream>
#include<cmath>
using namespace std;
double yuxian(int x1, int y1, int x2, int y2){
double result;
result = (x1*x2+y1*y2) / (sqrt(x1 * x1 + y1 * y1) * sqrt(x2 * x2 + y2 * y2));
return result;
}
double juli(int x1, int y1, int x2, int y2){
double result;
result = sqrt(pow(x1-x2, 2) + pow(y1-y2, 2));
return result;
}
int *bijiao(int x1,int y1, int x2, int y2, int x3, int y3){
double result1, result2, result3, result4;
result1 = yuxian(x1, y1, x2, y2);//小红与小明相似度
result2 = juli(x1, y1, x2, y2);
result3 = yuxian(x1, y1, x3, y3); // 小红与小张相似度
result4 = juli(x1, y1, x3, y3);
int *returnvalue = new int;
if (result1 > result3){
returnvalue[0] = 1; // 推荐流浪地球
} else returnvalue[0] = 0; // 推荐西红柿首富
if (result2 < result4){
returnvalue[1] = 1; // 推荐流浪地球
} else returnvalue[1] = 0; // 推荐西红柿首富
return returnvalue;
}
int main(){
int x1, y1, x2, y2, x3, y3;
cin >> x1 >> y1;
cin >> x2 >> y2;
cin >> x3 >> y3;
int *rv = new int;
rv = bijiao(x1, y1, x2, y2, x3, y3); // 调用比较函数
cout << rv[0] << endl; // 输出结果
cout << rv[1] << endl;
return 0;
}
```
拓展一个新的姿势,如果想让函数返回数组,则需要如`int *func(int par)`的声明,并且返回的数组必须用`int *sz = new int`声明
## 总结
这道题其实并不难,只要有数学基础,认真分析公式,就能解出来(应该不会还有人没发现,发题解的是作者吧)