(补题) 湖南省第六届大学生计算机程序设计竞赛

D - Ball in a Rectangle

题意:小球初始位置在(x,y),半径为r,以与水平正方向夹角α的初始速度v开始运动,在矩形边框内进行弹性碰撞,问s秒后小球球心位置在哪。

主要做法:浮点数取模。

做法概括:假设最初在(x,y),由于速度分解后属于弹性碰撞,那么对于每一维单独计算路程,然后用(路程+当前位置)模上周期,即可求得最终位置(需要进行简单判断)

详情见注释



#include<bits/stdc++.h>
#define ll long long
using namespace std;
const double pi = acos(-1);
const double eps = 1e-5;
const int maxn = 1e5 + 10;

inline int dcmp(double x)//cmp x with 0
{
    if (fabs(x) <= eps)return 0;
    return x < 0 ? -1 : 1;
}
inline int cmp(double x, double y)
{
    //x>y return 1
    //x<y reutrn -1
    //x==y return 0
    return dcmp(x - y);
}


int main() 
{
    double L, W, x, y, R, a, v, s;
    while (cin >> L >> W >> x >> y >> R >> a >> v >> s)
    {
        if (cmp(R, 0) == 0)break;
        double vx, vy;
        double rad = a / 180.0 * pi;
        L -= 2 * R, W -= 2 * R;//球心运动范围
        double X = 2.0 * L, Y = 2.0 * W;//周期计算
        x -= R, y -= R;//坐标原点变为(R,R)
        vx = v * cos(rad);
        vy = v * sin(rad);//速度分解
        double sx = fmod(x + s * vx, X), sy = fmod(y + s * vy, Y);//求最终位置并对周期取模
        double ansx, ansy;
        ansx = sx, ansy = sy;
        //判断最终答案
        if (-X / 2 < ansx && ansx < X / 2)
            ansx = fabs(ansx);
        else
            ansx = X - fabs(ansx);
        if (-Y / 2 < ansy && ansy < Y / 2)
            ansy = fabs(ansy);
        else
            ansy = Y - fabs(ansy);
        printf("%.2lf %.2lf\n", ansx + R, ansy + R);
    }
    return 0;
}


G - Repairing a Road

题意:给一个无向图,每条边有两个参数\(v\)和\(a\),\(v\)为不操作这条边时的时间代价(后面会讲),你需要从起点\(1\)走到终点\(n\)。其中你拥有一个仅可进行1次的操作,即假设你当前到达点\(i\)的时间为\(ti\),那么你这个操作就能使这个点所连的边的时间代价变为v*pow(a,-t)。让你求从起点到终点最小的时间代价。

如果没有这一次操作,那么就是个裸的最短路。但是加上了这个操作,那么就需要去判断在哪条边上进行操作,甚至需要在哪个时间点进行这个操作才能达到最优。

做法:先floyd跑出每两点之间的距离,然后去枚举每条边,这样就可以得到这条边的两个端点以及到1到这两个端点的最短路,然后决策什么时间修改这条边最优。

已经推得的公式是:\(f(t)=dis[1][x]+v[i]*pow(a[i],-t)+dis[y][n]\),其中x,y分别是边i的两个端点,t为啥时候修改枚举的这条边。对f(t)进行求导,得到:\(f'(t)=1 - log(a) * v * pow(a, -t)\),这个函数显然是单调递增的,并且极值对应的f(t)总是最小值,那么就二分一个t求出这个函数的极值点回带即可用其更新答案。

#include<bits/stdc++.h>
#define ll long long
#define fastio ios::sync_with_stdio(false),cin.tie(NULL),cout.tie(NULL)
using namespace std;

const double eps = 1e-5;
const int maxn = 1e5 + 10;

ll mod = 987654321;

int n, m;

int cnt;

struct edge {
    int from, to;
    double v, a;
}e[maxn];

double dis[110][110];

void init()
{
    for (int i = 1; i <= n; i++)
        for (int j = 1; j <= n; j++)
            dis[i][j] = (i == j ? 0 : maxn);
}

void floyd()
{
    for (int k = 1; k <= n; k++)
        for (int i = 1; i <= n; i++)
            for (int j = 1; j <= n; j++)
                dis[i][j] = min(dis[i][j], dis[i][k] + dis[k][j]);
}

double ans;

//f'(t) = 1 - ln(ai) * vi * ai ^ (-t)
double cal(int from, int to, double v, double a)
{
    double l = 0, r = 114514;
    while (r - l > eps)
    {
        //printf("%lf %lf\n", l, r);
        double mid = (l + r) / 2.0;
        if (1 - log(a) * v * pow(a, -mid) > 0)
            r = mid;
        else l = mid;
    }
    double tim;
    if (l < dis[1][from])
        tim = dis[1][from];
    else
        tim = l;
    return tim + v * pow(a, -tim) + dis[to][n];

}

void solve()
{
    for (int i = 1; i <= cnt; i++)
    {
        int from = e[i].from, to = e[i].to;
        double a = e[i].a, v = e[i].v;
        ans = min(ans, cal(from, to, v, a));
        ans = min(ans, cal(to, from, v, a));
    }
}

int main() 
{
    //fastio;
    while (cin >> n >> m, n, m)
    {
        cnt = 0;
        init();
        while (m--)
        {
            int x, y;
            double a, b;
            cin >> x >> y >> a >> b;
            e[++cnt] = { x,y,a,b };
            dis[x][y] = dis[y][x] = a;
        }
        floyd();
        ans = dis[1][n];
        solve();
        printf("%.3lf\n", ans);
    }
    return 0;
}



上一篇:Linux-vi编辑器简单使用(保证存活)


下一篇:603_linux内核学习_sys.c中用户名以及主机名处理