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

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

【问题描述】
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;
}

您可能感兴趣的与本文相关的镜像

Qwen-Image-Edit-2509

Qwen-Image-Edit-2509

图片编辑
Qwen

Qwen-Image-Edit-2509 是阿里巴巴通义千问团队于2025年9月发布的最新图像编辑AI模型,主要支持多图编辑,包括“人物+人物”、“人物+商品”等组合玩法

### 关于 SCOI2009 WINDY 数的解法 #### 定义与问题描述 WINDY数是指对于任意两个相邻位置上的数字,它们之间的差至少为\(2\)。给定正整数区间\([L, R]\),计算该范围内有多少个WINDY数。 #### 动态规划方法解析 为了高效解决这个问题,可以采用动态规划的方法来处理。定义状态`dp[i][j]`表示长度为`i`且高位是`j`的WINDY数的数量[^3]。 - **初始化** 对于单个数字的情况(即只有一位),显然每一位都可以单独构成一个合法的WINDY数,因此有: ```cpp dp[1][d] = 1; // d ∈ {0, 1,...,9} ``` - **状态转移方程** 当考虑多位数时,如果当前位选择了某个特定数值,则下一位的选择会受到限制——它必须满足与前一位相差不小于2的要求。具体来说就是当上一高位为`pre`时,当前位置可选范围取决于`pre`的具体取值: - 如果`pre >= 2`, 则可以选择`{0... pre-2}` - 否则只能从剩余的有效集合中选取 这样就可以通过遍历所有可能的状态来进行状态间的转换并累加结果。 - **边界条件处理** 特殊情况下需要注意的是,在实际应用过程中还需要考虑到给出区间的上下限约束。可以通过逐位比较的方式判断是否越界,并据此调整有效状态空间大小。 ```cpp // 计算不超过num的windy数数量 int calc(int num){ int f[15], g[15]; memset(f, 0, sizeof(f)); string s = to_string(num); n = s.size(); for (char c : s) { a[++len] = c - '0'; } // 初始化f数组 for (int i=0;i<=9;++i)f[1][i]=1; // DP过程省略... return sum; } long long solve(long long L,long long R){ return calc(R)-calc(L-1); } ``` 此代码片段展示了如何利用预处理好的`dp`表快速查询指定范围内的WINDY数总量。其中`solve()`函数用于返回闭区间\[L,R\]内符合条件的总数;而辅助函数`calc()`负责根据传入参数构建相应的状态序列并终得出答案。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值