|
|
@@ -247,6 +247,8 @@ int main() |
|
|
|
|
|
|
|
|
## THUAI6 |
|
|
## THUAI6 |
|
|
|
|
|
|
|
|
|
|
|
### high-ladder |
|
|
|
|
|
|
|
|
因为今年的对局得分是两局得分之和,所以会出现一定程度的“数值膨胀”,在这里调低了胜者得分权值,同时提高了比赛分差距悬殊阈值和天梯分差距悬殊阈值。同时由于今年得分的上限不好确定,所以负者失分的基础值变为与胜者的得分之差。 |
|
|
因为今年的对局得分是两局得分之和,所以会出现一定程度的“数值膨胀”,在这里调低了胜者得分权值,同时提高了比赛分差距悬殊阈值和天梯分差距悬殊阈值。同时由于今年得分的上限不好确定,所以负者失分的基础值变为与胜者的得分之差。 |
|
|
|
|
|
|
|
|
```c++ |
|
|
```c++ |
|
|
@@ -330,3 +332,126 @@ mypair<int> cal(mypair<int> orgScore, mypair<int> competitionScore) |
|
|
} |
|
|
} |
|
|
``` |
|
|
``` |
|
|
|
|
|
|
|
|
|
|
|
### competition |
|
|
|
|
|
|
|
|
|
|
|
与天梯得分算法要满足的“枫氏七条”类似,比赛得分算法也要满足“唐氏四律”,分别如下: |
|
|
|
|
|
|
|
|
|
|
|
1. 两队经过某场比赛的得分变化,应只与该场比赛有关,而与历史积分无关。 |
|
|
|
|
|
2. 须赋予比赛获胜一方基础得分,哪怕获胜一方的优势非常小。也就是说,哪怕胜利一方仅以微弱优势获胜,也需要拉开胜者与败者的分差。 |
|
|
|
|
|
3. 胜利一方优势越大,得分理应越高。 |
|
|
|
|
|
4. 对于一场比赛,胜利一方的得分不能无限大,须控制在一个合理的数值以下。 |
|
|
|
|
|
|
|
|
|
|
|
- 在非平局的情况下,(胜者)天梯得分与双方比赛分差值成正相关,得分函数如下(以x表示得分差值,y表示(胜者)天梯得分,a、b为固定参数) |
|
|
|
|
|
|
|
|
|
|
|
$$y=ax^2(1-0.375\cdot(\tanh(\frac{x}{b}-1)+1))$$ |
|
|
|
|
|
|
|
|
|
|
|
- 在平局情况下,(双方)天梯得分与比赛分成正相关,得分函数如下(以x表示比赛分,y表示(双方)天梯得分,c为固定参数) |
|
|
|
|
|
|
|
|
|
|
|
$$y=cx^2$$ |
|
|
|
|
|
|
|
|
|
|
|
- 不管是哪种情况,都有得分下界,非平局为100,平局为25 |
|
|
|
|
|
|
|
|
|
|
|
```c++ |
|
|
|
|
|
#include <iostream> |
|
|
|
|
|
#include <algorithm> |
|
|
|
|
|
#include <cmath> |
|
|
|
|
|
#include <cassert> |
|
|
|
|
|
using namespace std; |
|
|
|
|
|
|
|
|
|
|
|
template <typename T> |
|
|
|
|
|
using mypair = pair<T, T>; |
|
|
|
|
|
double minScore = 100; |
|
|
|
|
|
|
|
|
|
|
|
double TieScore(double gameScore) |
|
|
|
|
|
{ |
|
|
|
|
|
const double get = 9e-5; // 天梯得分权值 |
|
|
|
|
|
double deltaScore = 2000.0; // 订正的幅度,该值越小,则在双方分差较大时,天梯分数改变量越小,整个函数的变化范围大约为0~2*deltaScore |
|
|
|
|
|
double highScore = 6000.0; // 将highScore设定为较大值,使得correct较小 |
|
|
|
|
|
double correct = 1 - 0.375 * (tanh((highScore - deltaScore) / deltaScore) + 1.0); // 一场比赛中,在双方分差较大时,减小天梯分数的改变量 |
|
|
|
|
|
cout << "correct: " << correct << endl; |
|
|
|
|
|
int score = round(gameScore * gameScore * get * correct / 4); |
|
|
|
|
|
return score > minScore / 4 ? score : minScore / 4; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
double WinScore(double delta, double winnerGameScore) // 根据游戏得分差值,与绝对分数,决定最后的加分 |
|
|
|
|
|
{ |
|
|
|
|
|
assert(delta > 0); |
|
|
|
|
|
const double firstnerGet = 9e-5; // 胜利者天梯得分权值 |
|
|
|
|
|
double deltaScore = 2000.0; // 订正的幅度,该值越小,则在双方分差较大时,天梯分数改变量越小,整个函数的变化范围大约为0~2*deltaScore |
|
|
|
|
|
double correct = 1 - 0.375 * (tanh((delta - deltaScore) / deltaScore) + 1.0); // 一场比赛中,在双方分差较大时,减小天梯分数的改变量 |
|
|
|
|
|
cout << "correct: " << correct << endl; |
|
|
|
|
|
int score = round(delta * delta * firstnerGet * correct); |
|
|
|
|
|
return score > minScore ? score : minScore; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// orgScore 是天梯中两队的分数;competitionScore 是这次游戏两队的得分 |
|
|
|
|
|
mypair<double> cal(mypair<double> orgScore, mypair<double> competitionScore) |
|
|
|
|
|
{ |
|
|
|
|
|
// 调整顺序,让第一个元素成为获胜者,便于计算 |
|
|
|
|
|
|
|
|
|
|
|
bool reverse = false; // 记录是否需要调整 |
|
|
|
|
|
|
|
|
|
|
|
if (competitionScore.first < competitionScore.second) |
|
|
|
|
|
{ |
|
|
|
|
|
reverse = true; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
if (reverse) // 如果需要换,换两者的顺序 |
|
|
|
|
|
{ |
|
|
|
|
|
swap(competitionScore.first, competitionScore.second); |
|
|
|
|
|
swap(orgScore.first, orgScore.second); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
double delta = competitionScore.first - competitionScore.second; |
|
|
|
|
|
double addScore; |
|
|
|
|
|
mypair<double> resScore; |
|
|
|
|
|
|
|
|
|
|
|
// 先处理平局的情况 |
|
|
|
|
|
if (delta == 0) |
|
|
|
|
|
{ |
|
|
|
|
|
addScore = TieScore(competitionScore.first); |
|
|
|
|
|
resScore = mypair<double>(orgScore.first + addScore, orgScore.second + addScore); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// 再处理有胜负的情况 |
|
|
|
|
|
else |
|
|
|
|
|
{ |
|
|
|
|
|
addScore = WinScore(delta, competitionScore.first); |
|
|
|
|
|
resScore = mypair<double>(orgScore.first + addScore, orgScore.second); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// 如果换过,再换回来 |
|
|
|
|
|
if (reverse) |
|
|
|
|
|
{ |
|
|
|
|
|
swap(resScore.first, resScore.second); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
return resScore; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
void Print(mypair<double> score) |
|
|
|
|
|
{ |
|
|
|
|
|
std::cout << "team1: " << score.first << std::endl |
|
|
|
|
|
<< "team2: " << score.second << std::endl; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
int main() |
|
|
|
|
|
{ |
|
|
|
|
|
double x, y, t, i = 0; |
|
|
|
|
|
cin >> t; |
|
|
|
|
|
while (i < t) |
|
|
|
|
|
{ |
|
|
|
|
|
cout << "----------------------------------------\n"; |
|
|
|
|
|
std::cout << "origin score of team 1 and 2: " << std::endl; |
|
|
|
|
|
std::cin >> x >> y; |
|
|
|
|
|
auto ori = mypair<double>(x, y); |
|
|
|
|
|
std::cout << "game score of team 1 and 2: " << std::endl; |
|
|
|
|
|
std::cin >> x >> y; |
|
|
|
|
|
auto sco = mypair<double>(x, y); |
|
|
|
|
|
Print(cal(ori, sco)); |
|
|
|
|
|
++i; |
|
|
|
|
|
} |
|
|
|
|
|
return 0; |
|
|
|
|
|
} |
|
|
|
|
|
``` |
|
|
|
|
|
|