首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 更多程式語言 >> 程式設計綜合問答

C# LINQ 生成課程表:每天必含自修課的約束實現

     編輯:程式設計綜合問答

需求

  • 5 天 × 6 節課表。
  • 固定課程:語文、數學、英語各至少 1 節/天。
  • 體育、美術、音樂、勞動等選修課隨機分布。
  • 新增:每天必須有「自修課」。

核心邏輯調整

原代碼 while (!result.All(x => x.Contains("語文課") && ...)) 只檢查三門主科。**在條件中加入 && x.Contains("自修課") 即可**。

完整可運行代碼

using System;
using System.Linq;

namespace ScheduleGenerator {
    class Program {
        static void Main() {
            string[] courses = { "體育課", "體育課", "美術課", "音樂課", "勞動課",
                                 "語文課", "語文課", "語文課", "語文課", "語文課", "語文課", "語文課",
                                 "數學課", "數學課", "數學課", "數學課", "數學課", "數學課", "數學課",
                                 "英語課", "英語課", "英語課", "英語課", "英語課", "英語課", "英語課", "英語課" };

            string[][] result;
            do {
                result = Enumerable.Range(0, 5)
                    .Select(_ => Enumerable.Range(0, 6).Select(__ => "").ToArray())
                    .ToArray();

                var rndSeq = Enumerable.Range(0, 30)
                    .OrderBy(_ => Guid.NewGuid())
                    .Zip(courses, (i, c) => new { Index = i, Course = c })
                    .ToArray();

                for (int day = 0; day < 5; day++) {
                    int pos = 0;
                    string[] main = { "語文課", "數學課", "英語課" };
                    for (int period = 0; period < 6; period++) {
                        int idx = day * 6 + period;
                        var match = rndSeq.FirstOrDefault(x => x.Index == idx);
                        result[day][period] = match?.Course ?? (pos < 3 ? main[pos++] : "自修課");
                    }
                }
            } while (!result.All(row =>
                row.Contains("語文課") &&
                row.Contains("數學課") &&
                row.Contains("英語課") &&
                row.Contains("自修課")   // ★ 新增約束
            ));

            // 打印:列優先(每節課橫向看 5 天)
            for (int period = 0; period < 6; period++) {
                for (int day = 0; day < 5; day++) {
                    Console.Write(result[day][period] + "\t");
                }
                Console.WriteLine();
            }
        }
    }
}

關鍵點解析

  1. do-while 保證約束滿足才退出,避免死循環(課程池足夠大時極快收斂)。
  2. Guid.NewGuid() 作為隨機排序鍵,簡單有效。
  3. pos < 3 ? main[pos++] : "自修課" 確保三門主科優先填滿,其餘位置自動變自修課,天然滿足「每天有自修」——**前提是選修課池不超過 3 節/天**;若選修課可能更多,需顯式保留 1 格給自修課。
  4. 輸出轉置(列優先)符合人類閱讀習慣。

擴展建議

  • 用約束規劃求解器(如 Google OR-Tools CP-SAT)替代隨機試錯,保證最優解與硬約束。
  • 將課程池、約束規則外部化配置(JSON/DB),支援動態調整。
  • 加入「同課不相鄰」、「教師衝突」、「教室容量」等軟約束評分。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved