1 条题解

  • 0
    @ 2025-5-6 4:33:58

    解题思路:

    本题要求判断能否合理分发T恤,使得每位参赛者都能得到符合其接受范围的尺码。通过将问题建模为网络流的最大流问题,利用最大流算法求解。

    关键步骤:

    1. 问题建模

      • 将每位参赛者视为图中的节点,T恤尺码视为中间节点,源点连接参赛者,汇点连接尺码库存。
      • 参赛者与其可接受的尺码之间建立边,容量为1;尺码与汇点之间的边容量为该尺码的库存数量。
    2. 图结构设计

      • 源点0(0)到每位参赛者节点1X(1-X)的边容量为11
      • 参赛者节点到其可接受的尺码节点X+1X+5(X+1-X+5)的边容量为11
      • 尺码节点汇点X+6(X+6)的边容量为该尺码的库存数量。
    3. 最大流计算

      • 使用SAPSAP(最短增广路径)算法计算源点到汇点的最大流。
      • 若最大流等于参赛者人数XX,说明所有参赛者均可被满足。
    4. 输入处理

      • 将参赛者接受的尺码范围转换为数值区间,确保正确处理字符顺序(如MXMXXMXM均视为MMXX的范围)。

    C++实现:

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <queue>
    #include <algorithm>
    #include <stdio.h>
    using namespace std;
    
    const int maxn = 500;        // 最大节点数
    const int maxm = 500000;     // 最大边数
    const int INF = 1<<30;       // 无穷大定义
    
    int idx;                     // 边的索引计数器
    int cur[maxn], pre[maxn];    // 当前弧和前驱节点数组
    int dis[maxn], gap[maxn];    // 距离标号和间隙统计
    int aug[maxn], head[maxn];   // 可增广流量和邻接表头指针
    
    struct Node {
        int u, v, w;             // 边的起点、终点、容量
        int next;                // 下一条边索引
    } edge[maxm];
    
    // 将尺码字符转换为数值(S→1, M→2, L→3, X→4, T→5)
    int sol(char c) {
        if (c == 'S') return 1;
        if (c == 'M') return 2;
        if (c == 'L') return 3;
        if (c == 'X') return 4;
        if (c == 'T') return 5;
        return 0;
    }
    
    // 添加双向边(正向边和反向边)
    void addEdge(int u, int v, int w) {
        edge[idx].u = u;
        edge[idx].v = v;
        edge[idx].w = w;
        edge[idx].next = head[u];
        head[u] = idx++;
        // 反向边容量为0
        edge[idx].u = v;
        edge[idx].v = u;
        edge[idx].w = 0;
        edge[idx].next = head[v];
        head[v] = idx++;
    }
    
    // SAP算法(带GAP优化)计算最大流
    int SAP(int s, int e, int n) {
        int max_flow = 0, u = s;
        aug[s] = INF;
        pre[s] = -1;
        memset(dis, 0, sizeof(dis));
        memset(gap, 0, sizeof(gap));
        gap[0] = n;
        for (int i = 0; i <= n; ++i) 
            cur[i] = head[i];
        while (dis[s] < n) {
            bool flag = false;
            if (u == e) {
                max_flow += aug[e];
                for (int v = pre[e]; v != -1; v = pre[v]) {
                    int id = cur[v];
                    edge[id].w -= aug[e];
                    edge[id^1].w += aug[e];
                    aug[v] -= aug[e];
                    if (edge[id].w == 0) u = v;
                }
            }
            for (int id = cur[u]; id != -1; id = edge[id].next) {
                int v = edge[id].v;
                if (edge[id].w > 0 && dis[u] == dis[v] + 1) {
                    flag = true;
                    pre[v] = u;
                    cur[u] = id;
                    aug[v] = min(aug[u], edge[id].w);
                    u = v;
                    break;
                }
            }
            if (!flag) {
                int mindis = n;
                for (int id = head[u]; id != -1; id = edge[id].next) {
                    int v = edge[id].v;
                    if (edge[id].w > 0 && dis[v] < mindis) {
                        mindis = dis[v];
                        cur[u] = id;
                    }
                }
                if (--gap[dis[u]] == 0) break;
                dis[u] = mindis + 1;
                gap[dis[u]]++;
                if (u != s) u = pre[u];
            }
        }
        return max_flow;
    }
    
    int main() {
        char str[100];
        int n;
        while (scanf("%s", str) != EOF) {
            if (strcmp(str, "ENDOFINPUT") == 0) break;
            if (strcmp(str, "START") == 0) {
                scanf("%d", &n);
                idx = 0;
                memset(head, -1, sizeof(head));
                // 源点到参赛者的边(容量1)
                for (int i = 1; i <= n; ++i)
                    addEdge(0, i, 1);
                // 处理每个参赛者的尺码范围
                for (int i = 1; i <= n; ++i) {
                    char c1, c2;
                    scanf(" %c%c", &c1, &c2);
                    int a = sol(c1), b = sol(c2);
                    int s = min(a, b), e = max(a, b);
                    for (int j = s; j <= e; ++j)
                        addEdge(i, n + j, 1); // 连接到对应尺码节点
                }
                // 处理库存并连接到汇点
                int S, M, L, X, T;
                scanf("%d%d%d%d%d", &S, &M, &L, &X, &T);
                int sink = n + 6; // 汇点编号
                addEdge(n + 1, sink, S);
                addEdge(n + 2, sink, M);
                addEdge(n + 3, sink, L);
                addEdge(n + 4, sink, X);
                addEdge(n + 5, sink, T);
                // 读取END行
                scanf("%s", str);
                // 计算最大流
                int flow = SAP(0, sink, sink + 1);
                if (flow == n) 
                    printf("T-shirts rock!\n");
                else 
                    printf("I'd rather not wear a shirt anyway...\n");
            }
        }
        return 0;
    }
    
    • 1

    信息

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