306 lines
7.8 KiB
C
306 lines
7.8 KiB
C
#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;
|
||
} |