data-structure-experiments/6/main.c

306 lines
7.8 KiB
C
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
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;
}