#include #include #include int se; // 学期总数 int sx; // 学分上限 int cl; // 课程数量 int ren[12], fe[12], re[12][105]; typedef struct { char *id; // 课程编号 int sx; // 学分 int xq; int sel; // 是否已经选择 int pren, nexn; // 先修课程数量 int ppren; // use for topo char *pre[105]; // 先修课程 char *next[105]; // 后续课程 } Class; Class ss[105]; Class *queue[105]; int head = 0, tail = 0; void push(Class *c) { queue[tail++] = c; } Class *pop() { return queue[head++]; } int empty() { return head == tail; } Class *front() { return queue[head]; } void pt(int detail) { // print for (int i = 0; i < cl; i++) { printf("%s %d %d %d\n", ss[i].id, ss[i].sx, ss[i].pren, ss[i].nexn); if (!detail) continue; if (ss[i].pren > 0) { printf("pre:\n"); for (int j = 0; j < ss[i].pren; j++) { printf("%s ", ss[i].pre[j]); } printf("\n"); } if (ss[i].nexn > 0) { printf("next:\n"); for (int j = 0; j < ss[i].nexn; j++) { printf("%s ", ss[i].next[j]); } printf("\n"); } printf("\n"); } } // 寻找 id int fd(char *id) { for (int i = 0; i < cl; i++) { if (strcmp(ss[i].id, id) == 0) { return i; } } return -1; } char *substr(char *str, int start, int cnt) { char *res = (char *)malloc(sizeof(char) * (cnt + 1)); for (int i = 0; i < cnt; i++) { res[i] = str[start + i]; } res[cnt] = '\0'; return res; } // 去除字符串两边空格和换行符 char *ql(char *s) { char *res = (char *)malloc(sizeof(char) * (strlen(s) + 1)); int l = 0, r = strlen(s) - 1; while (s[l] == ' ' || s[l] == '\n') l++; while (s[r] == ' ' || s[r] == '\n') r--; for (int i = 0; i <= r - l; i++) { res[i] = s[l + i]; } return res; } // 寻找先修课程的最迟学期 int xz(int i) { // cout << ss[i].id << " " << ss[i].pren << endl; if (ss[i].pren == 0) return 0; int maxn = 0; for (int j = 0; j < ss[i].pren; j++) { int fid = fd(ss[i].pre[j]); if (ss[fid].xq > maxn) { maxn = ss[fid].xq; } } return maxn + 1; } // 寻找后修课程的最早学期 int xz2(int i) { if (ss[i].nexn == 0) return se; int minn = se; for (int j = 0; j < ss[i].nexn; j++) { int fid = fd(ss[i].next[j]); if (ss[fid].xq < minn) { minn = ss[fid].xq; } } return minn; } // 拓扑排序,将排好序的id 放入sorted void topo() { int sorted[105] = {0}; int cnt = 0; for (int i = 0; i < cl; i++) { if (ss[i].ppren == 0) { push(&ss[i]); } } while (!empty()) { Class *tmp = front(); sorted[cnt] = fd(tmp->id); pop(); cnt++; for (int i = 0; i < tmp->nexn; i++) { ss[fd(tmp->next[i])].ppren--; if (ss[fd(tmp->next[i])].ppren == 0) { push(&ss[fd(tmp->next[i])]); } } } if (cnt != cl) { printf("error\n"); exit(0); } Class newss[105]; // 将 ss 顺序改为 sorted 顺序 for (int i = 0; i < cl; i++) { newss[i] = ss[sorted[i]]; } for (int i = 0; i < cl; i++) { ss[i] = newss[i]; } } void avgf() { // 计算平均每学期学习数量 int avg = cl / se; // cout << avg << endl; // 按从后向前,如果学期学习数量小于平均值,则将前面的课程往后移动 for (int i = se - 1; i >= 1; i--) { if (ren[i] < avg) { for (int j = i - 1; j >= 0; j--) { // cout << j << " " << ren[j] << endl; if (ren[j] <= 0) continue; int flag = 0; for (int ii = 0; ii < ren[j] && ren[i] < avg; ii++) { int c = re[j][ii]; // cout << " " << ss[c].id << " " << xz2(2)<< endl; // cout << c << endl; if (xz2(c) > i) { // 把 c 课程放到 i 学期 re[i][ren[i]++] = c; ss[c].xq = i; // 把 c 课程从 j 学期删除 for (int jj = ii; jj < ren[j] - 1; jj++) { re[j][jj] = re[j][jj + 1]; } ren[j]--; flag = 1; } // 如果 i 学期中的课程数量大于平均值,则跳出循环 if (ren[i] >= avg) { break; } if (flag == 1) { ii = -1; flag = 0; } } } } } } void pte() { for (int i = 0; i < se; i++) { if (ren[i] == 0) continue; printf("学期 %d 学分 %d 课程数 %d 课程:", i + 1, fe[i], ren[i]); for (int j = 0; j < ren[i]; j++) { printf("%s ", ss[re[i][j]].id); } printf("\n"); } } int main() { freopen("in.txt", "r", stdin); scanf("%d%d", &se, &sx); if (se <= 0 || sx <= 0 || se > 6 || sx > 10) { printf("error\n"); exit(0); } scanf("%d", &cl); if (cl <= 0 || cl > 12) { printf("error\n"); exit(0); } for (int i = 0; i < cl; i++) { char *id = (char *)malloc(sizeof(char) * 105); scanf("%s", id); ss[i].id = ql(ss[i].id); } for (int i = 0; i < cl; i++) { scanf("%d", &ss[i].sx); scanf("%d", &ss[i].pren); ss[i].ppren = ss[i].pren; for (int j = 0; j < ss[i].pren; j++) { char *tmp = (char *)malloc(sizeof(char) * 105); scanf("%s", tmp); tmp = ql(tmp); if (strlen(tmp) == 0) continue; int fid = fd(tmp); if (fid == -1) { printf("error\n"); exit(0); } ss[i].pre[j] = ss[fid].id; ss[fid].next[ss[fid].nexn++] = ss[i].id; } } // pt(1); topo(); // pt(1); for (int i = 0; i < cl; i++) { ss[i].xq = xz(i); } int ttc = 0; for (int i = 0; i < se; i++) { for (int j = 0; j < cl; j++) { // 判断是否已选择 if (ss[j].sel == 1) { continue; } // 判断是否学分超过上限 if (ss[j].sx + fe[i] > sx) { continue; } // 判断是否先修课程已经学习 int flag = 0; for (int k = 0; k < ss[j].pren; k++) { int fid = fd(ss[j].pre[k]); if (ss[fid].sel == 0) { flag = 1; break; } } if (flag == 1) { continue; } // 选择该课程 ss[j].sel = 1; fe[i] += ss[j].sx; re[i][ren[i]++] = j; ttc++; } } // 判断是否全部选中 if (ttc != cl) { printf("error\n"); exit(0); } // for (int i = 0; i < cl; i++) { // cout << ss[i].id << " " << ss[i].xq << endl; // } // pte(); int kind; scanf("%d", &kind); if (kind != 1 && kind != 2) { printf("error\n"); exit(0); } // 输入分配方式,1是负担均匀,2是尽早学习 if (kind == 1) { avgf(); } else if (kind == 2) { // 本来就是今早分配的,无需更改 } else { printf("error\n"); exit(0); } // 输出最终结果 pte(); return 0; }