1 条题解
-
0
解题思路:
本题要求判断能否合理分发T恤,使得每位参赛者都能得到符合其接受范围的尺码。通过将问题建模为网络流的最大流问题,利用最大流算法求解。
关键步骤:
-
问题建模:
- 将每位参赛者视为图中的节点,T恤尺码视为中间节点,源点连接参赛者,汇点连接尺码库存。
- 参赛者与其可接受的尺码之间建立边,容量为1;尺码与汇点之间的边容量为该尺码的库存数量。
-
图结构设计:
- 源点到每位参赛者节点的边容量为。
- 参赛者节点到其可接受的尺码节点的边容量为。
- 尺码节点到汇点的边容量为该尺码的库存数量。
-
最大流计算:
- 使用(最短增广路径)算法计算源点到汇点的最大流。
- 若最大流等于参赛者人数,说明所有参赛者均可被满足。
-
输入处理:
- 将参赛者接受的尺码范围转换为数值区间,确保正确处理字符顺序(如和均视为到的范围)。
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
- 上传者