2018暑期练习题1 B 雾雨魔理沙

2018暑期练习题1 B 雾雨魔理沙

问题描述

在幻想乡,雾雨魔理沙是住在魔法之森普通的黑魔法少女。话说最近魔理沙从香霖堂拿到了升级过后的的迷你八卦炉,她迫不及待地希望试试八卦炉的威力。在一个二维平面上有许多毛玉(一种飞行生物,可以视为点),每个毛玉具有两个属性,分值value和倍率mul。八卦炉发射出的魔法炮是一条无限长的直线形区域,可以视为两条倾斜角为α的平行线之间的区域,平行线之间的距离可以为任意值。

蓝色部分上下两条长边之间就是这次八卦炉的攻击范围,在蓝色范围内的毛玉(红点)属于该此被击中的毛玉,如果一个毛玉刚好在边界上也视为被击中。毛玉击中以后就会消失,每次发射八卦炉得到分值是该次击中毛玉的分值和乘上这些毛玉平均的倍率,设该次击中的毛玉集合为S,则分值计算公式为:

Score=SUMvalue[i]|iSSUMmul[i]|iS/|S| S c o r e = S U M v a l u e [ i ] | i 属 于 S ∗ S U M m u l [ i ] | i 属 于 S / | S |

其中|S|表示S的元素个数。魔理沙将会使用若干次八卦炉,直到把所有毛玉全部击中。任意两次攻击的范围均不重叠。最后得到的分值为每次攻击分值之和。现在请你计算出能够得到的最大分值。

输入格式

第1行:1个整数N,表示毛玉个数

第2..N+1行:每行四个整数x, y, value, mul,表示星星的坐标(x,y),以及value和mul

第N+2行:1个整数α,表示倾斜角角度,0°到180°

输出格式

第1行:1个实数,表示最大分值,保留三位小数

解法

不知道该怎么讲…直接放伪代码吧

1.把点按从上到下(或者从下到上)的顺序排序(斜率已知,点的坐标已知,可以求出截距)

2.动态规划: f[i]=f[j]+sumj+1,i,0<=j<i f [ i ] = f [ j ] + s u m j + 1 , i , 0 <= j < i ,其中sum{j+1,i}表示 j+1 j + 1 i i <script type="math/tex" id="MathJax-Element-27">i</script>号点的分值(总分*平均倍率)

代码

我这代码还把同一条直线上的点合并了,因为它们肯定会被一根直线消掉

然而并没有这个必要,徒增代码复杂度,害我调了好久= =

#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
#define pi 3.1415926
#define N 2100
using namespace std;
struct node{int x,y,v,mul,id;}p[N];
struct Node{int v,mul,Size;double b;}New[N];
double Max(double a,double b){return a>b?a:b;}
bool cmp(node a,node b){return a.id<b.id;}
bool cmpp(Node aa,Node bb){return aa.b<bb.b;}
double f[N];
int main(){
    int n;scanf("%d",&n);
    for(int i=1;i<=n;i++){
        scanf("%d%d%d%d",&p[i].x,&p[i].y,&p[i].v,&p[i].mul);
        p[i].id=i;
    }
    double al;scanf("%lf",&al);
    al=tan(pi*al/180);
    for(int i=1;i<=n;i++)
        for(int j=i+1;j<=n;j++){
            if(p[j].id!=j)continue;
            double k=(double)(p[j].y-p[i].y)/(p[j].x-p[i].x);
            if(k==al)p[j].id=i;
        }
    sort(p+1,p+n+1,cmp);int cnt=0;
    for(int i=1;i<=n;i++){
        if(p[i].id!=p[i-1].id)cnt++;
        New[cnt].v+=p[i].v,New[cnt].mul+=p[i].mul,New[cnt].Size++;
        New[cnt].b=1.0*p[i].y-al*p[i].x;
    }
    sort(New+1,New+cnt+1,cmpp);
    for(int i=1;i<=cnt;i++)
        New[i].v+=New[i-1].v,New[i].mul+=New[i-1].mul,New[i].Size+=New[i-1].Size;
    for(int i=1;i<=cnt;i++)
        for(int j=0;j<i;j++)
            f[i]=Max(f[i],f[j]+1.0*(New[i].v-New[j].v)*(New[i].mul-New[j].mul)/(New[i].Size-New[j].Size));
    printf("%.3lf",f[cnt]);return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值