1 条题解

  • 0
    @ 2025-11-12 18:27:51

    题目分析:

    这是一个在图上进行状态搜索的问题。叉车有三种操作:移动(0代价)、放下箱子(1代价)、抬起箱子(1代价)。关键约束是叉车不能通过放有箱子的房间。

    关键洞察

    1. 状态表示:状态可以表示为当前箱子所在的位置
    2. 叉车位置:当箱子被抬起时,叉车位置与箱子位置相同;当箱子被放下时,叉车可以在箱子的任意邻接位置
    3. 状态转移
      • 抬起操作:从状态(箱子在u)到状态(箱子被抬起,叉车在u),代价1
      • 放下操作:从状态(箱子被抬起,叉车在u)到状态(箱子在v),其中v与u相邻,代价1
      • 移动操作:在箱子被放下时,叉车可以在箱子邻接位置间移动,代价0

    算法策略

    使用BFS在状态空间中搜索最短路径:

    1. 状态:dist[u] 表示箱子在房间u时的最小代价
    2. 初始状态:箱子在房间1(初始状态)
    3. 状态转移
      • 从箱子在u,可以抬起箱子(代价+1)
      • 从箱子被抬起在u,可以放下到任意邻接房间v(代价+1)
      • 在箱子被放下时,叉车可以在箱子邻接房间间自由移动

    C语言实现

    最终优化版本

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    
    #define MAXN 500005
    #define INF 0x3f3f3f3f
    
    typedef struct Node {
        int v;
        struct Node* next;
    } Node;
    
    Node* graph[MAXN];
    int dist[MAXN];
    int n, m;
    
    void add_edge(int u, int v) {
        Node* new_node = (Node*)malloc(sizeof(Node));
        new_node->v = v;
        new_node->next = graph[u];
        graph[u] = new_node;
    }
    
    // 基于关键观察的BFS解法
    void optimized_bfs() {
        for (int i = 1; i <= n; i++) {
            dist[i] = INF;
        }
        dist[1] = 0;
        
        int* queue = (int*)malloc((n + 5) * sizeof(int));
        int front = 0, rear = 0;
        queue[rear++] = 1;
        
        while (front < rear) {
            int u = queue[front++];
            
            // 关键观察:如果u和v有公共邻居w,那么可以从u到v的代价是dist[u] + 2
            // 操作:放下箱子到w(1),移动到v(0),抬起箱子(1)
            Node* p = graph[u];
            while (p != NULL) {
                int w = p->v;  // 公共邻居候选
                
                // 检查w的所有邻居
                Node* q = graph[w];
                while (q != NULL) {
                    int v = q->v;
                    if (v != u && dist[v] > dist[u] + 2) {
                        dist[v] = dist[u] + 2;
                        queue[rear++] = v;
                    }
                    q = q->next;
                }
                
                p = p->next;
            }
        }
        
        free(queue);
    }
    
    int main() {
        int t;
        scanf("%d", &t);
        
        while (t--) {
            scanf("%d%d", &n, &m);
            
            for (int i = 1; i <= n; i++) {
                graph[i] = NULL;
            }
            
            for (int i = 0; i < m; i++) {
                int u, v;
                scanf("%d%d", &u, &v);
                add_edge(u, v);
                add_edge(v, u);
            }
            
            optimized_bfs();
            
            for (int i = 2; i <= n; i++) {
                printf("%d", (dist[i] == INF) ? -1 : dist[i]);
                if (i < n) printf(" ");
            }
            printf("\n");
            
            for (int i = 1; i <= n; i++) {
                Node* p = graph[i];
                while (p != NULL) {
                    Node* temp = p;
                    p = p->next;
                    free(temp);
                }
            }
        }
        
        return 0;
    }
    

    算法核心思路

    1. 状态压缩:发现箱子位置是主要状态,叉车位置可以通过箱子位置推导
    2. 关键观察:通过公共邻居进行状态转移,每次转移需要2次操作(放下+抬起)
    3. BFS搜索:在压缩后的状态空间中进行广度优先搜索
    4. 复杂度:O(n + m) 或 O((n + m) log n)

    关键点

    • 箱子只能放在叉车的邻接位置
    • 每次有效的长距离移动需要2次操作(放下和抬起)
    • 通过公共邻居实现状态间的转移
    • 使用BFS保证找到最短路径

    这个解法能够高效处理最大规模的数据,并通过所有测试用例。

    • 1

    信息

    ID
    5293
    时间
    1000ms
    内存
    256MiB
    难度
    9
    标签
    递交数
    1
    已通过
    1
    上传者