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;

}

 

posted @ 2012-04-15 16:37  LETTers  阅读(235)  评论(0编辑  收藏  举报