【最短路径】【SCOI2009】最长距离

本文深入探讨了游戏开发领域的关键技术,包括游戏引擎、编程语言、硬件优化等,以及AI音视频处理在游戏中的应用,如语义识别、语音变声等。通过分析现有技术和案例,为游戏开发者提供技术指导。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

【问题描述】
windy有一块矩形土地,被分为 N*M 块 1*1 的小格子。
有的格子含有障碍物。
如果从格子A可以走到格子B,那么两个格子的距离就为两个格子中心的欧几里德距离。
如果从格子A不可以走到格子B,就没有距离。
如果格子X和格子Y有公共边,并且X和Y均不含有障碍物,就可以从X走到Y。
如果windy可以移走T块障碍物,求所有格子间的最大距离。
保证移走T块障碍物以后,至少有一个格子不含有障碍物。

【输入格式】
输入文件maxlength.in第一行包含三个整数,N M T。
接下来有N行,每行一个长度为M的字符串,'0'表示空格子,'1'表示该格子含有障碍物。

【输出格式】
输出文件maxlength.out包含一个浮点数,保留6位小数。

【输入样例一】
3 3 0
001
001
110

【输出样例一】
1.414214

【输入样例二】
4 3 0
001
001
011
000

【输出样例二】
3.605551

【输入样例三】
3 3 1
001
001
001

【输出样例三】
2.828427

【数据规模和约定】
20%的数据,满足 1 <= N,M <= 30 ; 0 <= T <= 0 。
40%的数据,满足 1 <= N,M <= 30 ; 0 <= T <= 2 。
100%的数据,满足 1 <= N,M <= 30 ; 0 <= T <= 30 。
此题考察最短路径。

建图时,将每个点向它的上下左右各连一条边,边的权值为改变两顶点上障碍的数目之和。

然后对每个点进行一次SPFA,将所有与其距离不超过2T的点到该点的最大距离找出来,再取所有的最大距离即为所求。

提交情况:提交五次。
第一次:0分。(TimeLimitExceed * 10,须用链表解决。)
第二次:20分。(WrongAnswer * 8,建图有误。)
第三次:10分。(WrongAnswer * 9,建图有误。)
第四次:70分。(WrongAnswer * 3)
第五次:100分。
Accode:

#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>

const char fi[] = "maxlength.in";
const char fo[] = "maxlength.out";
const int maxR = 40;
const int maxN = 1010;
const int SIZE = 1000000;
const int MAX = 0x3f3f3f3f;
const int MIN = ~MAX;
const int dx[] = {1, -1, 0, 0};
const int dy[] = {0, 0, 1, -1};

struct Edge
{
    int u, v, d;
    Edge *next;
};

int dist[maxR][maxR];
Edge *edge[maxR][maxR];
int q[SIZE][2];
bool obs[maxR][maxR];
bool marked[maxR][maxR];
int x[maxN];
int y[maxN];
int n, m, T, tot, f, r;
double ans, init;

void init_file()
{
	freopen(fi, "r", stdin);
	freopen(fo, "w", stdout);
	return;
}

double sqr(double x) {return x * x; }

double d(double x1, double y1,
         double x2, double y2)
{
    return sqrt(sqr(x1 - x2) + sqr(y1 - y2));
}

void insert(int x, int y, int u, int v, int d)
{
    Edge *p = new Edge;
    p -> u = u;
    p -> v = v;
    p -> d = d;
    p -> next = edge[x][y];
    edge[x][y] = p;
}

void readdata()
{
    scanf("%d%d%d", &n, &m, &T);
    for (int i = 1; i < n + 1; ++i)
    {
        getchar();
        for (int j = 1; j < m + 1; ++j)
        {
            obs[i][j] = getchar() - '0';
            if (obs[i][j])
            {
                x[++tot] = i;
                y[tot] = j;
            }
        }
    }
    for (int i = 1; i < n + 1; ++i)
    for (int j = 1; j < m + 1; ++j)
    for (int k = 0; k < 4; ++k)
    {
        int i1 = i + dx[k],
        j1 = j + dy[k];
        if (i1 < 1 || i1 > n || j1 < 1 || j1 > m)
            continue;
        insert(i, j, i1, j1,
               obs[i][j] + obs[i1][j1]);
    }
	return;
}

void Enq(int X, int Y)
{
    q[r][0] = X;
    q[r][1] = Y;
    if (++r > SIZE) r -= SIZE;
    return;
}

int Front_x()
{
    return q[f][0];
}

int Front_y()
{
    return q[f][1];
}

void Deq()
{
    if (++f > SIZE) f -= SIZE;
    return;
}

void Spfa(int X, int Y)
{
    f = r = 0;
    memset(dist, 0x3f, sizeof(dist));
    memset(marked, 0, sizeof(marked));

    Enq(X, Y);
    marked[X][Y] = 1;
    dist[X][Y] = 0; //细节处应注意。

    while (f != r)
    {
        int _x = Front_x();
        int _y = Front_y();
        Deq(); //细节处应注意。
        marked[_x][_y] = 0;
        for (Edge *p = edge[_x][_y]; p; p = p -> next)
        {
            int _u = p -> u, _v = p -> v;
            if (dist[_x][_y] + p -> d < dist[_u][_v])
            {
                dist[_u][_v] = dist[_x][_y] + p -> d;
                if (!marked[_u][_v])
                {
                    Enq(_u, _v);
                    marked[_u][_v] = 1;
                }
            }
        }
    }
    return;
}

void work()
{
    init = sqrt(sqr(n - 1) + sqr(m - 1));
    for (int i = 1; i < n + 1; ++i)
    for (int j = 1; j < m + 1; ++j)
    if (!obs[i][j])
	//要从一个非障碍点出发,且两端不能同时为非障碍点。
    {
        Spfa(i, j);
        for (int i1 = 1; i1 < n + 1; ++i1)
        for (int j1 = 1; j1 < m + 1; ++j1)
        if (i1 != i || j1 != j)
        {
            double tmp = d(i, j, i1, j1);
            if (dist[i1][j1] <= (T << 1) && tmp > ans)
                ans = tmp;
        }
    }
    printf("%.6lf\n", ans);
	return;
}

int main()
{
	init_file();
	readdata();
	work();
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值