LETTers练习赛十一场解题报告

第1题解题报告

提交人:蔡驰宇

提交日期:2012.05.09

题目描述

很水的一道题,实际上就是一个三角形求重心的问题,套用公式就好了。

程序

#include<iostream>

#include<cmath>

using namespace std;

const int inf=1<<29;

const int M=50200;

const double eps=1e-8;

struct point

{

    double x,y;

}po[5],p,g;

int n;

int main()

{

    int T,i;

    while(scanf("%d",&T)==1)

    {

        if(!T) break;

        while(T--)

        {

            for(int i=0;i<3;i++)

                scanf("%lf%lf",&po[i].x,&po[i].y);

            double tp,area=0,tpx=0,tpy=0;

            p.x=po[0].x;

            p.y=po[0].y;

            for(i=1;i<=3;i++)

            {

                g.x=po[(i==3)?0:i].x;

                g.y=po[(i==3)?0:i].y;

                tp=(p.x*g.y-p.y*g.x);

                area+=tp/2;

                tpx=tpx+(p.x+g.x)*tp;

                tpy=tpy+(p.y+g.y)*tp;

                p.x=g.x;

                p.y=g.y;

            }

            g.x=tpx/(6*area);

            g.y=tpy/(6*area);

            printf("%.1lf %.1lf\n",g.x,g.y);

        }

    }

    return 0;

}

第2题解题报告

题目描述

一个二分法的题目,原理并不难,但是在计算时要注意精度,High和Low判断相等的过程中精度要达到10^-9以上才能AC。

程序

#include <iostream>

#include <cmath>

using namespace std;

#define N 10005

#define EPS 1e-10

double elem[N];

int n,m;

int judge(double x)

{

       int i;

       int count=0;

       for(i=0;i<n;i++)

       {

              count+=(int)(elem[i]/x);

       }

       if(count>=m)

              return 1;

       else return 0;

}

int main()

{

       int i;

       double MAX=0,low,high,mid;

       while(scanf("%d%d",&n,&m),m+n)

       {

              for(i=0;i<n;i++)

              {

                     scanf("%lf",&elem[i]);

                     MAX+=elem[i];

              }

              MAX/=m;

              low=0;

              high=MAX;

              while(fabs(low-high)>EPS)

              {

                     mid=(low+high)/2;

                     if(judge(mid)==1)

                            low=mid;

                     else

                            high=mid;

              }

              printf("%.2lf/n",low);

       }

       return 0;

}

第3题解题报告

题目描述

一个较为典型的母函数应用,由题意可知,相同的硬币可以重复,那就为可重复组合。

构造函数G(x)=(1+x+x^2+…)(1+x^4+x^8+…)…(1+x^289+x^578+…)。

程序

#include<stdio.h>

#include<string.h>

#define MAXD 20

#define MAXM 310

int f[MAXD][MAXM], N;

void prepare()

{

    int i, j, k;

    memset(f, 0, sizeof(f));

    f[0][0] = 1;

    for(i = 1; i <= 17; i ++)

        for(j = 0; j <= 300; j += i * i)

            for(k = 0; k + j <= 300; k ++)

                f[i][k + j] += f[i - 1][k];

}

int main()

{

    prepare();

    for(;;)

    {

        scanf("%d", &N);

        if(!N)

            break;

        printf("%d\n", f[17][N]);

    }

    return 0;

}

第4题解题报告

题目描述

封锁出口或者入口周围的格子.

最多需要4个封锁点.

所以我们可以采取这样的策略:

1.寻找一条盗贼的可行路线,如果没有,返回0.

2.计算封锁出口和入口四周需要的封锁点数量,取小的一个,假设是k,k <=4

3.从少到多,遍历所有封锁点个数小于k的方案,验证是否是一条有效的覆盖方案

(可以通过是否阻止了1中的盗贼线路进行快速验证).

如果有有效覆盖方案,返回这个方案的覆盖点值,否则继续.

4.如果没有比k小的覆盖方案,返回k.

时间复杂度:

最多(M*N)^3次有效覆盖验证.即(8*8)^3=256k次.其中有很大一部分可以通过快速验证排除(取决于1的路径长短,所以一般1应该求出最短路径的可行路线)

程序

#include <iostream>

#include <queue>

#include <string>

using namespace std;

int n,m,t,ans;

int dir[4][2] = {1,0,-1,0,0,-1,0,1};

char map[10][10];

bool vis[2][10][10];

struct node

{

    int x,y,t,k;//x,y为坐标,t为时间,k为是否有碰到宝石

    int rox[64],roy[64];//用来保存路径的,每个节点都保存有一条路径,只有到达终点后才有完整的路径

};

node start,end,temp,in;

queue <node> Q;

void dfs(int deep)

{

    if(deep > ans) return ;

    int i,j,minstep = -1;

    node q;

    while(!Q.empty())//清空队列

        Q.pop();

    Q.push(start);//起始位置入队

    memset(vis,false,sizeof(vis));//初始化标记数组

    vis[0][start.x][start.y] = true;//标记起始点为真

    while(!Q.empty())//从起点开始寻找一条路径

    {

        q = Q.front();

        Q.pop();

        if(q.t > t)

            continue;

        if(q.k && map[q.x][q.y] == 'E')//找到出口

        {

            minstep = q.t;

            break;

        }

        for(i = 0;i < 4;i++)//分别从四个方向开始扫描

        {

            int xx = q.x + dir[i][0];

            int yy = q.y + dir[i][1];

            if(xx < 0 || xx >= n || yy < 0 || yy >= m || map[xx][yy] == '#')

                continue;//越界或碰到墙

            if(map[xx][yy] == 'J')

                in.k = 1;//碰到珠宝

            else

                in.k = q.k;//没有碰到则标记为前一个状态

            if(!vis[in.k][xx][yy])

            {

                vis[in.k][xx][yy] = true;

                for(j = 1;j <= q.t;j++) //将前一节点保存的路径加入到现在的节点,由于是按顺序的,所以他会形成连贯的路线

                {

                    in.rox[j] = q.rox[j];

                    in.roy[j] = q.roy[j];

                }

                in.x = xx;

                in.y = yy;

                in.t = q.t + 1;

                //这个节点的第in.t步保存的是xx,yy

                in.rox[in.t] = xx;

                in.roy[in.t] = yy;

                Q.push(in);

            }

        }

    }

    if(minstep == -1)

    {// minstep == -1 表明在t时间内即使不用设置关卡也不能成功逃离

        if(deep < ans)

            ans = deep;

        return ;

    }

    char cc;

    for(i = 1;i < q.t;i++)

    {

        cc = map[q.rox[i]][q.roy[i]];

        if(cc == 'S' || cc == 'E')

            continue;

        map[q.rox[i]][q.roy[i]] = '#';//在做完前面的bfs后,这里的q是到达终点的节点,因此他完整的保存了一条路

        dfs(deep+1);

        map[q.rox[i]][q.roy[i]] = cc ;

    }

}

void inits()

{

    int i,j;

    memset(vis,false,sizeof(vis));

    for(i = 0;i < n;i++)

        for(j = 0;j < m;j++)

        {

            if(map[i][j] == 'S')

            {

                start.x = i;start.y = j;

                start.t = 0;start.k = 0;

                break;

            }

        }

        ans = 4;

        dfs(0);

        printf("%d\n",ans);

}

int main()

{

    int i,cas;

    scanf("%d",&cas);

    while(cas--)

    {

        scanf("%d%d%d",&n,&m,&t);

        for(i = 0;i < n;i++)

            scanf("%s",map[i]);

        inits();

    }

    return 0;

}

原文地址:https://www.cnblogs.com/LETTers/p/2492661.html