LETTers比赛第二场解题报告
LETTers比赛第二场解题报告:
提交人:周杰
第一题:典型的威佐夫博奕,具体解法请大家参考程序中的吧,有现成的公式,有兴趣的同学可以试试去查下证明过程。
AC程序之一:
#include <stdio.h>
#include <math.h>
int a, b, temp, k;
int result;
int main (int argc, char* argv[]) {
while (scanf("%d %d", &a, &b) != -1) {
if (a > b) {
temp = a;
a = b;
b = temp;
}
k = b - a;
result = (int)((k * (1.0 + sqrt(5))) / 2.0);
if (result == a && b == (a + k)) printf("0\n");
else printf("1\n");
}
return 0;
}
第二题:这道题是典型的计算几何,出自2011年北京赛区地区赛。其实注意点也没啥,就是注意重点的判断和共线即可。。其他的大家自己体会吧。精度问题也要注意。
参考程序:
#include <iostream>
#include <algorithm>
#include <cmath>
using namespace std;
#define EP 1e-8
struct point{ //点
double x, y;
}p[20];
struct trangle{ //三角形(特征:2个角的(余弦值*2))
double A, B;
}tra[10005];
bool hash[205][205], vis[10005];
double dist (point a, point b) //欧式距离求边长
{
return sqrt ((a.x-b.x)*(a.x-b.x) + (a.y-b.y)*(a.y-b.y));
}
bool multi (point a, point b, point c) //叉积判断三点是否共线
{
double x1, y1, x2, y2;
x1 = b.x - a.x;
y1 = b.y - a.y;
x2 = c.x - b.x;
y2 = c.y - b.y;
int tp = x1 * y2 - x2 * y1;
if (tp == 0)
return false;
return true;
}
bool similar (trangle a, trangle b) //余弦值对应比较判定相似,2个角即可
{
if (fabs (a.A-b.A) <= EP && fabs (a.B-b.B) <= EP)
return true;
return false;
}
int main()
{
double e[3];
int n, i, j, k, num, tp, maxs;
while (scanf ("%d", &n), n)
{
memset (hash, false, sizeof(hash));
for (i = 0; i < n; i++)
{
scanf ("%lf%lf", &p[i].x, &p[i].y);
if (hash[(int)p[i].x+100][(int)p[i].y+100]) //出现过的点就不再要了
i--, n--;
hash[(int)p[i].x+100][(int)p[i].y+100] = true;
}
num = 0; //累计合法三角形个数
for (i = 0; i < n; i++) //获取所有合法三角形存放到tra
{
for (j = i + 1; j < n; j++)
{
for (k = j + 1; k < n; k++)
{
if (!multi (p[i], p[j], p[k])) //判定三角形合法性
continue;
e[0] = dist (p[i], p[j]);
e[1] = dist (p[i], p[k]);
e[2] = dist (p[j], p[k]);
sort (e, e+3); //三边排序实现对应比较
double a = e[0];
double b = e[1];
double c = e[2];
tra[num].A = (b*b + c*c - a*a)/b/c; //直接用(余弦值*2)对应判定
tra[num].B = (a*a + c*c - b*b)/a/c;
num++;
}
}
}
maxs = 0;
memset (vis, false, sizeof(vis));
for (i = 0; i < num; i++) //以一个三角形为基准往下比较数相似三角形
{
if (vis[i]) //已经访问过的就不必再以它为准了
continue;
tp = 1;
for (j = i + 1; j < num; j++)
{
if (vis[j])
continue;
if (similar (tra[i], tra[j]))
tp++, vis[j] = true;
}
if (tp > maxs)
maxs = tp;
}
printf ("%d\n", maxs);
}
}
第三题:搜索+博弈。其实说是有博弈,只是用深搜搜索一个叫‘SG值’的东西,具体‘SG值’是啥,大家可以百度下。
参考程序:
#include <iostream>
#include <cstdio>
using namespace std;
const int N = 55;
char map[N][N];
int m, n;
int judge(int i, int j){
if(map[i][j] == '0' && map[i][j+1] == '0' && map[i+1][j] == '0' && map[i+1][j+1] == '0'){
map[i][j] = map[i][j+1] = map[i+1][j] = map[i+1][j+1] = '1';
return 1;
}
return 0;
}
void recover(int i, int j){
map[i][j] = map[i][j+1] = map[i+1][j] = map[i+1][j+1] = '0';
}
int dfs(){
for(int i = 0; i < n; i++){
for(int j = 0; j < m; j++){
if(judge(i, j)){
if(!dfs()){
recover(i, j);
return 1;
}
recover(i, j);
}
}
}
return 0;
}
int main(){
freopen("data.in", "r", stdin);
while(~scanf("%d%d", &n, &m)){
getchar();
for(int i = 0; i < n; i++){
for(int j = 0; j < m; j++){
scanf("%c", &map[i][j]);
}
getchar();
}
if(dfs()) puts("Yes");
else puts("No");
}
return 0;
}
第四题:朴素动态规划。设dp[i][j]为第i回合剩余魔法值为j的时候可以造成的最大伤害值。那么状态转移方程为:tmp = Min(100, j – magic[k] + t);
Dp[i][tmp] = Max(dp[i][tmp], dp[i-1][j] + damage[k]);
剩下的就是边界处理了。
参考程序:
#include <cstdlib>
#include <cctype>
#include <cstring>
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <vector>
#include <string>
#include <iostream>
#include <sstream>
#include <map>
#include <set>
#include <queue>
#include <stack>
#include <fstream>
#include <numeric>
#include <iomanip>
#include <bitset>
#include <list>
#include <stdexcept>
#include <functional>
#include <utility>
#include <ctime>
#include <memory.h>
using namespace std;
template<class T> inline T Max(T a,T b)
{if(a>b)return a;else return b;}
template<class T> inline T Min(T a,T b)
{if(a<b)return a;else return b;}
#define ll long long
#define For(i, a, b) for (int (i) = (a); (i) < (b); (i)++)
#define DFor(i, b, a) for (int (i) = (b) - 1; (i) >= (a); (i)--)
int n, t, q;
int magic[105];
int damage[105];
int dp[105][105];
int tmp;
int maxl;
int judge, ans;
void init () {
memset(magic, 0, sizeof(magic));
memset(damage, 0, sizeof(damage));
memset(dp, 0, sizeof(dp));
ans = 0;
}
int main (int argc, const char* argv[]) {
while (scanf("%d %d %d", &n, &t, &q) && n + t + q) {;
init();
damage[0] = 1;
magic[0] = 0;
For(i, 1, n + 1) {
scanf("%d %d", &magic[i], &damage[i]);
}
For(i, 1, n + 1) {
For(j, 1, n + 1) {
dp[i][j] = -9999999;
}
}
judge = 0;
dp[0][100] = 0;
maxl = (int)ceil(100.0 / q);
For(i, 1, maxl + 1) {
For(j, 1, 101) {
For(k, 0, n + 1) {
if (j >= magic[k]) {
tmp = Min(100, j - magic[k] + t);
dp[i][tmp] = Max(dp[i][tmp], dp[i-1][j] + damage[k]);
if (dp[i][tmp] >= 100) {
judge = 1;
ans = i;
break;
}
}
}
if (judge == 1) break;
}
if (judge == 1) break;
}
if (judge == 1) printf("%d\n", ans);
else printf("My god\n");
}
return 0;
}