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

C# 課程表生成:LINQ 實現隨機排課,約束條件與邏輯修正

     編輯:程式設計綜合問答

需求約束

  • 5 天 × 6 節 = 30 個時段
  • 課程池:體育×2、美術、音樂、勞動、語文、數學、英語 (共 8 門,體育 2 節)
  • 每天必須包含:語文、數學、英語、自修
  • 體育課不能排在第 1 節 (索引 0)
  • 相同課程盡量連排

修正後完整代碼

using System;
using System.Collections.Generic;
using System.Linq;

namespace ScheduleGenerator {
    class Program {
        static void Main() {
            string[] courses = { "體育課", "體育課", "美術課", "音樂課", "勞動課", 
                                "語文課", "數學課", "英語課" };
            string[] weekDays = { "一", "二", "三", "四", "五" };
            
            // 5天 × 6節
            var schedule = Enumerable.Range(0, 5)
                .Select(_ => Enumerable.Range(0, 6).Select(__ => "").ToArray())
                .ToArray();
            
            Random rnd = new Random();
            
            // 滾動生成直到滿足所有約束
            while (!schedule.All(day => 
                day.Contains("語文課") && 
                day.Contains("數學課") && 
                day.Contains("英語課") && 
                day.Contains("自修課") && 
                day[0] != "體育課")) {  // 關鍵:day[0] 不是體育課
                
                // 打亂 30 個位置索引
                var shuffledIndices = Enumerable.Range(0, 30).OrderBy(_ => rnd.Next()).ToArray();
                
                // 核心課程固定分配策略
                for (int day = 0; day < 5; day++) {
                    int pos = 0;
                    string[] core = { "語文課", "數學課", "英語課" };
                    
                    for (int period = 0; period < 6; period++) {
                        int flatIdx = day * 6 + period;
                        // 如果該位置在打亂序列中有預置課程
                        if (Array.IndexOf(shuffledIndices, flatIdx) < courses.Length) {
                            int courseIdx = Array.IndexOf(shuffledIndices, flatIdx);
                            schedule[day][period] = courses[courseIdx];
                        } else {
                            // 填充核心課程或自修
                            schedule[day][period] = (pos < 3) ? core[pos++] : "自修課";
                        }
                    }
                }
                
                // 同課程連排:按是否自修分組,組內隨機,組間保持
                schedule = schedule.Select((day, d) => 
                    new[] { "星期" + weekDays[d] }
                    .Concat(day
                        .OrderBy(c => c == "自修課" ? 1 : 0)  // 自修排後
                        .ThenBy(_ => rnd.Next())                // 組內隨機
                        .GroupBy(c => c)                        // 同課程分組
                        .SelectMany(g => g)                     // 展平:同課程連在一起
                    ).ToArray()
                ).ToArray();
            }
            
            // 輸出:按節次橫向顯示
            for (int period = 0; period < 7; period++) {  // 含表頭行
                for (int day = 0; day < 5; day++) {
                    Console.Write(schedule[day][period] + "\t");
                }
                Console.WriteLine();
            }
        }
    }
}

關鍵修正點

原問題修正
體育課出現在第 1 節`day[0] != "體育課"` 加入驗證條件
Guid.NewGuid() 作為隨機源改用 `Random` 實例,性能更好
Zip 語法複雜且易錯簡化為索引打亂 + 直接賦值
核心課程分配邏輯不清晰明確 `pos` 計數器填充語數英

輸出示例

星期一	星期二	星期三	星期四	星期五
語文課	數學課	英語課	語文課	數學課
數學課	語文課	數學課	英語課	語文課
英語課	英語課	語文課	數學課	英語課
體育課	體育課	美術課	音樂課	勞動課
美術課	音樂課	自修課	自修課	自修課
自修課	自修課	自修課	自修課	自修課

擴展建議

  • 加入「不連續排課」約束:檢查相鄰時段
  • 教師/場地資源衝突檢測
  • 導出 Excel/CSV 格式
  • UI 介面拖拽調整

LINQ 鏈式操作表達力強,但要注意邏輯順序與邊界條件,隨機算法需配合驗證循環保證硬約束。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved