日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 综合教程 >内容正文

综合教程

C# 解决组合优化问题

發(fā)布時間:2024/1/3 综合教程 27 生活家
生活随笔 收集整理的這篇文章主要介紹了 C# 解决组合优化问题 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

Google Optimization Tools介紹

Google Optimization Tools(OR-Tools)是一款專門快速而便攜地解決組合優(yōu)化問題的套件。它包含了:

約束編程求解器。

簡單而統(tǒng)一的接口,用于多種線性規(guī)劃和混合整數(shù)規(guī)劃求解,包括 CBC、CLP、GLOP、GLPK、Gurobi、CPLEX 和SCIP。

圖算法 (最短路徑、最小成本、最大流量、線性求和分配)。

經(jīng)典旅行推銷員問題和車輛路徑問題的算法。

經(jīng)典裝箱和背包算法。

Google使用C++開發(fā)了OR-Tools庫,但支持Python,C#,或Java語言調(diào)用。

安裝Google OR-Tools
Google OR-Tools的源碼在[Github] google/or-tools。其它開發(fā)環(huán)境下的安裝如下。

Linux or Mac下安裝

確認(rèn)使用了Python 2.7+,3.5+版本,以及pip 9.0.1+版本。

Mac OSX系統(tǒng)需要安裝命令行工具Xcode,在Terminal中執(zhí)行xcode-select --install。

Linux系統(tǒng)需要安裝g++,在Terminal中執(zhí)行sudo apt-get install g++ make。

如果使用C#請確認(rèn)安裝了Mono 4.2.0+的64位版本。

在Terminal中執(zhí)行pip install --upgrade ortools直接安裝Python版本的OR-Tools包。C++/Java/C#版本的鏈接為:Mac, Ubuntu 17.04, Ubuntu 16.04, Ubuntu 14.04, CentOS 7, Debian 9 ,下載到指定目錄后執(zhí)行make all。

Windows下安裝
Python版本的包的安裝和Linux一樣,可自行選用合適的開發(fā)工具。若是使用C++、C#,推薦使用64位版本的Windows10操作系統(tǒng),并且使用Microsoft Visual Studio 2015 或者 2017作為開發(fā)工具,相應(yīng)的庫文件下載地址為: Visual Studio 2017 the Visual Studio 2015。

C++使用lib/ortools.lib, 并且將or?tools/include添加到項(xiàng)目引用。
Java使用jar命令調(diào)用lib/com.google.ortools.lib的方式,并且將 ?Djava.library.path=PATH_TO_or?tools/lib添加到命令行。
C#添加bin/Google.OrTools.dll到項(xiàng)目依賴,或者使用NuGet搜索Google.OrTools進(jìn)行安裝。
Demo
以下是幾種支持語言的demo,運(yùn)行一下驗(yàn)證是否安裝正確。

C++ 代碼

復(fù)制代碼

include "ortools/linear_solver/linear_solver.h"

include "ortools/linear_solver/linear_solver.pb.h"

namespace operations_research {
void RunTest(
MPSolver::OptimizationProblemType optimization_problem_type) {
MPSolver solver("Glop", optimization_problem_type);
MPVariable* const x = solver.MakeNumVar(0.0, 1, "x");
MPVariable* const y = solver.MakeNumVar(0.0, 2, "y");
MPObjective* const objective = solver.MutableObjective();
objective->SetCoefficient(x, 1);
objective->SetCoefficient(y, 1);
objective->SetMaximization();
solver.Solve();
printf("
Solution:");
printf("
x = %.1f", x->solution_value());
printf("
y = %.1f", y->solution_value());
}

void RunExample() {
RunTest(MPSolver::GLOP_LINEAR_PROGRAMMING);
}
}

int main(int argc, char** argv) {
operations_research::RunExample();
return 0;
}
復(fù)制代碼

C# 代碼

復(fù)制代碼
using System;
using Google.OrTools.LinearSolver;

public class my_program
{
private static void RunLinearProgrammingExample(String solverType)
{
Solver solver = Solver.CreateSolver("IntegerProgramming", solverType);
Variable x = solver.MakeNumVar(0.0, 1.0, "x");
Variable y = solver.MakeNumVar(0.0, 2.0, "y");
Objective objective = solver.Objective();
objective.SetCoefficient(x, 1);
objective.SetCoefficient(y, 1);
objective.SetMaximization();
solver.Solve();
Console.WriteLine("Solution:");
Console.WriteLine("x = " + x.SolutionValue());
Console.WriteLine("y = " + y.SolutionValue());
}

static void Main()
{
RunLinearProgrammingExample("GLOP_LINEAR_PROGRAMMING");
}
}
復(fù)制代碼

Python 代碼

復(fù)制代碼
from future import print_function
from ortools.linear_solver import pywraplp

def main():
solver = pywraplp.Solver('SolveSimpleSystem',
pywraplp.Solver.GLOP_LINEAR_PROGRAMMING)
x = solver.NumVar(0, 1, 'x')
y = solver.NumVar(0, 2, 'y')
objective = solver.Objective()
objective.SetCoefficient(x, 1)
objective.SetCoefficient(y, 1)
objective.SetMaximization()
solver.Solve()
print('Solution:')
print('x = ', x.solution_value())
print('y = ', y.solution_value())

if name == 'main':
main()
復(fù)制代碼

Java 代碼

復(fù)制代碼
import com.google.ortools.linearsolver.MPConstraint;
import com.google.ortools.linearsolver.MPObjective;
import com.google.ortools.linearsolver.MPSolver;
import com.google.ortools.linearsolver.MPVariable;

public class my_program {
static { System.loadLibrary("jniortools"); }

private static MPSolver createSolver (String solverType) {
return new MPSolver("my_program",
MPSolver.OptimizationProblemType.valueOf(solverType));
}

private static void runmy_program(String solverType,
boolean printModel) {
MPSolver solver = createSolver(solverType);
MPVariable x = solver.makeNumVar(0.0, 1.0, "x");
MPVariable y = solver.makeNumVar(0.0, 2.0, "y");
MPObjective objective = solver.objective();
objective.setCoefficient(y, 1);
objective.setMaximization();
solver.solve();
System.out.println("Solution:");
System.out.println("x = " + x.solutionValue());
System.out.println("y = " + y.solutionValue());
}

public static void main(String[] args) throws Exception {
runmy_program("GLOP_LINEAR_PROGRAMMING", false);
}
}
復(fù)制代碼

執(zhí)行結(jié)果如圖:

使用.Net Core與Google Optimization Tools實(shí)現(xiàn)員工排班計劃Scheduling

讓大家初步了解了Google Optimization Tools是一款約束求解(CP)的高效套件。那么我們用.Net Core與Google Optimization Tools來實(shí)現(xiàn)一個有關(guān)員工排班計劃的場景感受一下。

眾所周知,現(xiàn)實(shí)生活中有些工作是7X24工作制的,如呼叫中心或醫(yī)院護(hù)士,最常見的問題就是如何安排多名員工進(jìn)行倒班,制定好日程時間表,使每班配備足夠的人員來維持運(yùn)營。時間表有各種不同的約束要求,例如:員工不允許連續(xù)兩次輪班之類。接下來我們介紹類似問題的一個示例,叫護(hù)士調(diào)度問題,并展示了如何使用.Net Core與Google Optimization Tools實(shí)現(xiàn)排班計劃。

護(hù)士調(diào)度問題
在本例中,醫(yī)院主管需要為四名護(hù)士創(chuàng)建一個周時間表,具體情況如下:

每天分為早、中、晚三班輪班。
在每一天,所有護(hù)士都被分配到不同的班次,除了有一名護(hù)士可以休息。
每位護(hù)士每周工作五到六天。
每個班次不會有超過兩名護(hù)士在工作。
如果一名護(hù)士某一天的班次是中班或晚班,她也必須在前一日或次日安排相同的班次。
有兩種方式來描述我們需要解決的問題:

指派護(hù)士輪班
將班次分配給護(hù)士
事實(shí)證明,解決問題的最好方法是結(jié)合兩種方式來求解。

指派護(hù)士輪班
下表顯示了指派護(hù)士輪班視角的排班情況,這些護(hù)士被標(biāo)記為A,B,C,D,換班,編號為0 - 3(其中0表示護(hù)士當(dāng)天不工作)。

星期日

星期一 星期二 星期三 星期四 星期五 星期六
班次1
A
B
A
A
A
A
A
班次2
C
C
C
B
B
B
B
班次3
D
D
D
D
C
C
D
將班次分配給護(hù)士
下表顯示了將班次分配給護(hù)士視角的排班情況。

星期日	星期一	星期二	星期三	星期四	星期五	星期六

護(hù)士A 1 0 1 1 1 1 1
護(hù)士B 0 1 0 2 2 2 2
護(hù)士C 2 2 2 0 3 3 0
護(hù)士D 3 3 3 3 0 0 3

.Net Core解決方案
首先使用VS017創(chuàng)建一個.Net Core的控制臺項(xiàng)目。

由于Google Optimization Tools對.Net Core的支持還不友好,需要通過NuGet引用一個第三方專門為Core編譯好的程序集以及相關(guān)依賴,Google.OrTools.Core和CrossPlatformLibraryLoader。

準(zhǔn)備完成后,我們逐一介紹編碼的過程。首先介紹幾個基本概念:

IntVar是約束求解中使用最多的變量形式,一般約束問題中變化的對象都應(yīng)該定義為一個類似在一定范圍內(nèi)整形數(shù)值的變量。
solver.MakeIntVar是創(chuàng)建約束求解中變量的方法,約束求解一定會定義一些可變化的對象,一般都需要轉(zhuǎn)化成數(shù)值類型。
solver.Add是添加若干約束條件的方法。
solver.MakePhase定義了求解的目標(biāo)以及求解的取值策略。
solver.Solve進(jìn)行求解,并對指定的集合賦值。
solver.MakeAllSolutionCollector表示獲取解的集合對象。
定義約束求解器和相關(guān)變量
我們用shift和nurse分別來表示班次和護(hù)士 。

復(fù)制代碼
// 創(chuàng)建約束求解器.
var solver = new Solver("schedule_shifts");
var num_nurses = 4;
var num_shifts = 4; // 班次數(shù)定為4,這樣序號為0的班次表示是休息的班。
var num_days = 7;

    // [START]
    // 創(chuàng)建班次變量
    var shifts = new Dictionary<(int, int), IntVar>();

    foreach (var j in Enumerable.Range(0, num_nurses))
    {
        foreach (var i in Enumerable.Range(0, num_days))
        {
            // shifts[(j, i)]表示護(hù)士j在第i天的班次,可能的班次的編號范圍是:[0, num_shifts)
            shifts[(j, i)] = solver.MakeIntVar(0, num_shifts - 1, string.Format("shifts({0},{1})", j, i));
        }
    }

    // 將變量集合轉(zhuǎn)成扁平化數(shù)組
    var shifts_flat = (from j in Enumerable.Range(0, num_nurses)
                       from i in Enumerable.Range(0, num_days)
                       select shifts[(j, i)]).ToArray();

    // 創(chuàng)建護(hù)士變量
    var nurses = new Dictionary<(int, int), IntVar>();

    foreach (var j in Enumerable.Range(0, num_shifts))
    {
        foreach (var i in Enumerable.Range(0, num_days))
        {
            // nurses[(j, i)]表示班次j在第i天的當(dāng)班護(hù)士,可能的護(hù)士的編號范圍是:[0, num_nurses)
            nurses[(j, i)] = solver.MakeIntVar(0, num_nurses - 1, string.Format("shift{0} day{1}", j, i));
        }
    }

復(fù)制代碼
shifts和nurses兩個對象含義如下:

shifts[(j, i)]表示護(hù)士j在第i天的班次,可能的班次的編號范圍是:[0, num_shifts)。
nurses[(j, i)]表示班次j在第i天的當(dāng)班護(hù)士,可能的護(hù)士的編號范圍是:[0, num_nurses)。
shifts_flat是將shifts的Values簡單地處理成扁平化,后面直接用于當(dāng)參數(shù)傳給約束求解器solver以指定需要求解的變量。

定義shifts和nurses的對應(yīng)關(guān)系
將每一天的nurses單獨(dú)列出來,按照編號順序扁平化成一個數(shù)組對象,s.IndexOf(nurses_for_day)是一種OR-Tools要求的特定用法,相當(dāng)于nurses_for_day[s]求值。這里利用了s的值恰好是在nurses_for_day中對應(yīng)nurse的編號。注意這里的兩層foreach循環(huán),v外層不能互換,必須是現(xiàn)在這樣,內(nèi)層循環(huán)的主體對象與shifts_flat一致。

復(fù)制代碼
// 定義shifts和nurses之前的關(guān)聯(lián)關(guān)系
foreach (var day in Enumerable.Range(0, num_days))
{
var nurses_for_day = (from j in Enumerable.Range(0, num_shifts)
select nurses[(j, day)]).ToArray();
foreach (var j in Enumerable.Range(0, num_nurses))
{
var s = shifts[(j, day)];
// s.IndexOf(nurses_for_day)相當(dāng)于nurses_for_day[s]
// 這里利用了s的值恰好是在nurses_for_day中對應(yīng)nurse的編號
solver.Add(s.IndexOf(nurses_for_day) == j);
}
}
復(fù)制代碼

定義護(hù)士在不同的班次當(dāng)班約束
AllDifferent方法是OR-Tools定義約束的方法之一,表示指定的IntVar數(shù)組在進(jìn)行計算時受唯一性制約。滿足每一天的當(dāng)班護(hù)士不重復(fù),即每一天的班次不會出現(xiàn)重復(fù)的護(hù)士的約束條件,同樣每一個護(hù)士每天不可能同時輪值不同的班次。

復(fù)制代碼
// 滿足每一天的當(dāng)班護(hù)士不重復(fù),每一天的班次不會出現(xiàn)重復(fù)的護(hù)士的約束條件
// 同樣每一個護(hù)士每天不可能同時輪值不同的班次
foreach (var i in Enumerable.Range(0, num_days))
{
solver.Add((from j in Enumerable.Range(0, num_nurses)
select shifts[(j, i)]).ToArray().AllDifferent());
solver.Add((from j in Enumerable.Range(0, num_shifts)
select nurses[(j, i)]).ToArray().AllDifferent());
}
復(fù)制代碼

定義護(hù)士每周當(dāng)班次數(shù)的約束
Sum方法是OR-Tools定義運(yùn)算的方法之一。注意shifts[(j, i)] > 0運(yùn)算被重載過,其返回類型是WrappedConstraint而不是默認(rèn)的bool。滿足每個護(hù)士在一周范圍內(nèi)只出現(xiàn)[5, 6]次。

復(fù)制代碼
// 滿足每個護(hù)士在一周范圍內(nèi)只出現(xiàn)[5, 6]次
foreach (var j in Enumerable.Range(0, num_nurses))
{
solver.Add((from i in Enumerable.Range(0, num_days)
select shifts[(j, i)] > 0).ToArray().Sum() >= 5);
solver.Add((from i in Enumerable.Range(0, num_days)
select shifts[(j, i)] > 0).ToArray().Sum() <= 6);
}
復(fù)制代碼

定義每個班次在一周內(nèi)當(dāng)班護(hù)士人數(shù)的約束
Max方法是OR-Tools定義運(yùn)算的方法之一,表示對指定的IntVar數(shù)組求最大值。注意MakeBoolVar方法返回類型是IntVar而不是默認(rèn)的bool,works_shift[(i, j)]為True表示護(hù)士i在班次j一周內(nèi)至少要有1次,BoolVar類型的變量最終取值是0或1,同樣也表示了False或True。滿足每個班次一周內(nèi)不會有超過兩名護(hù)士當(dāng)班工作。

復(fù)制代碼
// 創(chuàng)建一個工作的變量,works_shift[(i, j)]為True表示護(hù)士i在班次j一周內(nèi)至少要有1次
// BoolVar類型的變量最終取值是0或1,同樣也表示了False或True
var works_shift = new Dictionary<(int, int), IntVar>();

    foreach (var i in Enumerable.Range(0, num_nurses))
    {
        foreach (var j in Enumerable.Range(0, num_shifts))
        {
            works_shift[(i, j)] = solver.MakeBoolVar(string.Format("nurse%d shift%d", i, j));
        }
    }

    foreach (var i in Enumerable.Range(0, num_nurses))
    {
        foreach (var j in Enumerable.Range(0, num_shifts))
        {
            // 建立works_shift與shifts的關(guān)聯(lián)關(guān)系
            // 一周內(nèi)的值要么為0要么為1,所以Max定義的約束是最大值,恰好也是0或1,1表示至少在每周輪班一天
            solver.Add(works_shift[(i, j)] == (from k in Enumerable.Range(0, num_days)
                                               select shifts[(i, k)].IsEqual(j)).ToArray().Max());
        }
    }

    // 對于每個編號不為0的shift, 滿足至少每周最多同一個班次2個護(hù)士當(dāng)班
    foreach (var j in Enumerable.Range(1, num_shifts - 1))
    {
        solver.Add((from i in Enumerable.Range(0, num_nurses)
                    select works_shift[(i, j)]).ToArray().Sum() <= 2);
    }

復(fù)制代碼

定義護(hù)士在中班和晚班的連班約束
復(fù)制代碼
// 滿足中班或晚班的護(hù)士前一天或后一天也是相同的班次
// 用nurses的key中Tuple類型第1個item的值表示shift為2或3
// shift為1表示早班班次,shift為0表示休息的班次
solver.Add(solver.MakeMax(nurses[(2, 0)] == nurses[(2, 1)], nurses[(2, 1)] == nurses[(2, 2)]) == 1);
solver.Add(solver.MakeMax(nurses[(2, 1)] == nurses[(2, 2)], nurses[(2, 2)] == nurses[(2, 3)]) == 1);
solver.Add(solver.MakeMax(nurses[(2, 2)] == nurses[(2, 3)], nurses[(2, 3)] == nurses[(2, 4)]) == 1);
solver.Add(solver.MakeMax(nurses[(2, 3)] == nurses[(2, 4)], nurses[(2, 4)] == nurses[(2, 5)]) == 1);
solver.Add(solver.MakeMax(nurses[(2, 4)] == nurses[(2, 5)], nurses[(2, 5)] == nurses[(2, 6)]) == 1);
solver.Add(solver.MakeMax(nurses[(2, 5)] == nurses[(2, 6)], nurses[(2, 6)] == nurses[(2, 0)]) == 1);
solver.Add(solver.MakeMax(nurses[(2, 6)] == nurses[(2, 0)], nurses[(2, 0)] == nurses[(2, 1)]) == 1);

    solver.Add(solver.MakeMax(nurses[(3, 0)] == nurses[(3, 1)], nurses[(3, 1)] == nurses[(3, 2)]) == 1);
    solver.Add(solver.MakeMax(nurses[(3, 1)] == nurses[(3, 2)], nurses[(3, 2)] == nurses[(3, 3)]) == 1);
    solver.Add(solver.MakeMax(nurses[(3, 2)] == nurses[(3, 3)], nurses[(3, 3)] == nurses[(3, 4)]) == 1);
    solver.Add(solver.MakeMax(nurses[(3, 3)] == nurses[(3, 4)], nurses[(3, 4)] == nurses[(3, 5)]) == 1);
    solver.Add(solver.MakeMax(nurses[(3, 4)] == nurses[(3, 5)], nurses[(3, 5)] == nurses[(3, 6)]) == 1);
    solver.Add(solver.MakeMax(nurses[(3, 5)] == nurses[(3, 6)], nurses[(3, 6)] == nurses[(3, 0)]) == 1);
    solver.Add(solver.MakeMax(nurses[(3, 6)] == nurses[(3, 0)], nurses[(3, 0)] == nurses[(3, 1)]) == 1);

復(fù)制代碼

定義約束求解器的使用
復(fù)制代碼
// 將變量集合設(shè)置為求解的目標(biāo),Solver有一系列的枚舉值,可以指定求解的選擇策略。
var db = solver.MakePhase(shifts_flat, Solver.CHOOSE_FIRST_UNBOUND, Solver.ASSIGN_MIN_VALUE);

    // 創(chuàng)建求解的對象
    var solution = solver.MakeAssignment();
    solution.Add(shifts_flat);
    var collector = solver.MakeAllSolutionCollector(solution);

復(fù)制代碼

執(zhí)行求解計算并顯示結(jié)果
復(fù)制代碼
solver.Solve(db, new[] { collector });
Console.WriteLine("Solutions found: {0}", collector.SolutionCount());
Console.WriteLine("Time: {0}ms", solver.WallTime());
Console.WriteLine();

    // 顯示一些隨機(jī)的結(jié)果
    var a_few_solutions = new[] { 340, 2672, 7054 };

    foreach (var sol in a_few_solutions)
    {
        Console.WriteLine("Solution number {0}", sol);

        foreach (var i in Enumerable.Range(0, num_days))
        {
            Console.WriteLine("Day {0}", i);
            foreach (var j in Enumerable.Range(0, num_nurses))
            {
                Console.WriteLine("Nurse {0} assigned to task {1}", j, collector.Value(sol, shifts[(j, i)]));
            }
            Console.WriteLine();
        }
    }

復(fù)制代碼
運(yùn)行結(jié)果如下:

最后,放出完整的代碼如下

復(fù)制代碼
using Google.OrTools.ConstraintSolver;
using System;
using System.Collections.Generic;
using System.Linq;

public class ConsoleApp1
{
static void Main()
{
// 創(chuàng)建約束求解器.
var solver = new Solver("schedule_shifts");
var num_nurses = 4;
var num_shifts = 4; // 班次數(shù)定為4,這樣序號為0的班次表示是休息的班。
var num_days = 7;

    // [START]
    // 創(chuàng)建班次變量
    var shifts = new Dictionary<(int, int), IntVar>();

    foreach (var j in Enumerable.Range(0, num_nurses))
    {
        foreach (var i in Enumerable.Range(0, num_days))
        {
            // shifts[(j, i)]表示護(hù)士j在第i天的班次,可能的班次的編號范圍是:[0, num_shifts)
            shifts[(j, i)] = solver.MakeIntVar(0, num_shifts - 1, string.Format("shifts({0},{1})", j, i));
        }
    }

    // 將變量集合轉(zhuǎn)成扁平化數(shù)組
    var shifts_flat = (from j in Enumerable.Range(0, num_nurses)
                       from i in Enumerable.Range(0, num_days)
                       select shifts[(j, i)]).ToArray();

    // 創(chuàng)建護(hù)士變量
    var nurses = new Dictionary<(int, int), IntVar>();

    foreach (var j in Enumerable.Range(0, num_shifts))
    {
        foreach (var i in Enumerable.Range(0, num_days))
        {
            // nurses[(j, i)]表示班次j在第i天的當(dāng)班護(hù)士,可能的護(hù)士的編號范圍是:[0, num_nurses)
            nurses[(j, i)] = solver.MakeIntVar(0, num_nurses - 1, string.Format("shift{0} day{1}", j, i));
        }
    }

    // 定義shifts和nurses之前的關(guān)聯(lián)關(guān)系
    foreach (var day in Enumerable.Range(0, num_days))
    {
        var nurses_for_day = (from j in Enumerable.Range(0, num_shifts)
                              select nurses[(j, day)]).ToArray();
        foreach (var j in Enumerable.Range(0, num_nurses))
        {
            var s = shifts[(j, day)];
            // s.IndexOf(nurses_for_day)相當(dāng)于nurses_for_day[s]
            // 這里利用了s的值恰好是在nurses_for_day中對應(yīng)nurse的編號
            solver.Add(s.IndexOf(nurses_for_day) == j);
        }
    }

    // 滿足每一天的當(dāng)班護(hù)士不重復(fù),每一天的班次不會出現(xiàn)重復(fù)的護(hù)士的約束條件
    // 同樣每一個護(hù)士每天不可能同時輪值不同的班次
    foreach (var i in Enumerable.Range(0, num_days))
    {
        solver.Add((from j in Enumerable.Range(0, num_nurses)
                    select shifts[(j, i)]).ToArray().AllDifferent());
        solver.Add((from j in Enumerable.Range(0, num_shifts)
                    select nurses[(j, i)]).ToArray().AllDifferent());
    }

    // 滿足每個護(hù)士在一周范圍內(nèi)只出現(xiàn)[5, 6]次
    foreach (var j in Enumerable.Range(0, num_nurses))
    {
        solver.Add((from i in Enumerable.Range(0, num_days)
                    select shifts[(j, i)] > 0).ToArray().Sum() >= 5);
        solver.Add((from i in Enumerable.Range(0, num_days)
                    select shifts[(j, i)] > 0).ToArray().Sum() <= 6);
    }

    // 創(chuàng)建一個工作的變量,works_shift[(i, j)]為True表示護(hù)士i在班次j一周內(nèi)至少要有1次
    // BoolVar類型的變量最終取值是0或1,同樣也表示了False或True
    var works_shift = new Dictionary<(int, int), IntVar>();

    foreach (var i in Enumerable.Range(0, num_nurses))
    {
        foreach (var j in Enumerable.Range(0, num_shifts))
        {
            works_shift[(i, j)] = solver.MakeBoolVar(string.Format("nurse%d shift%d", i, j));
        }
    }

    foreach (var i in Enumerable.Range(0, num_nurses))
    {
        foreach (var j in Enumerable.Range(0, num_shifts))
        {
            // 建立works_shift與shifts的關(guān)聯(lián)關(guān)系
            // 一周內(nèi)的值要么為0要么為1,所以Max定義的約束是最大值,恰好也是0或1,1表示至少在每周輪班一天
            solver.Add(works_shift[(i, j)] == (from k in Enumerable.Range(0, num_days)
                                               select shifts[(i, k)].IsEqual(j)).ToArray().Max());
        }
    }

    // 對于每個編號不為0的shift, 滿足至少每周最多同一個班次2個護(hù)士當(dāng)班
    foreach (var j in Enumerable.Range(1, num_shifts - 1))
    {
        solver.Add((from i in Enumerable.Range(0, num_nurses)
                    select works_shift[(i, j)]).ToArray().Sum() <= 2);
    }

    // 滿足中班或晚班的護(hù)士前一天或后一天也是相同的班次
    // 用nurses的key中Tuple類型第1個item的值表示shift為2或3
    // shift為1表示早班班次,shift為0表示休息的班次
    solver.Add(solver.MakeMax(nurses[(2, 0)] == nurses[(2, 1)], nurses[(2, 1)] == nurses[(2, 2)]) == 1);
    solver.Add(solver.MakeMax(nurses[(2, 1)] == nurses[(2, 2)], nurses[(2, 2)] == nurses[(2, 3)]) == 1);
    solver.Add(solver.MakeMax(nurses[(2, 2)] == nurses[(2, 3)], nurses[(2, 3)] == nurses[(2, 4)]) == 1);
    solver.Add(solver.MakeMax(nurses[(2, 3)] == nurses[(2, 4)], nurses[(2, 4)] == nurses[(2, 5)]) == 1);
    solver.Add(solver.MakeMax(nurses[(2, 4)] == nurses[(2, 5)], nurses[(2, 5)] == nurses[(2, 6)]) == 1);
    solver.Add(solver.MakeMax(nurses[(2, 5)] == nurses[(2, 6)], nurses[(2, 6)] == nurses[(2, 0)]) == 1);
    solver.Add(solver.MakeMax(nurses[(2, 6)] == nurses[(2, 0)], nurses[(2, 0)] == nurses[(2, 1)]) == 1);

    solver.Add(solver.MakeMax(nurses[(3, 0)] == nurses[(3, 1)], nurses[(3, 1)] == nurses[(3, 2)]) == 1);
    solver.Add(solver.MakeMax(nurses[(3, 1)] == nurses[(3, 2)], nurses[(3, 2)] == nurses[(3, 3)]) == 1);
    solver.Add(solver.MakeMax(nurses[(3, 2)] == nurses[(3, 3)], nurses[(3, 3)] == nurses[(3, 4)]) == 1);
    solver.Add(solver.MakeMax(nurses[(3, 3)] == nurses[(3, 4)], nurses[(3, 4)] == nurses[(3, 5)]) == 1);
    solver.Add(solver.MakeMax(nurses[(3, 4)] == nurses[(3, 5)], nurses[(3, 5)] == nurses[(3, 6)]) == 1);
    solver.Add(solver.MakeMax(nurses[(3, 5)] == nurses[(3, 6)], nurses[(3, 6)] == nurses[(3, 0)]) == 1);
    solver.Add(solver.MakeMax(nurses[(3, 6)] == nurses[(3, 0)], nurses[(3, 0)] == nurses[(3, 1)]) == 1);

    // 將變量集合設(shè)置為求解的目標(biāo),Solver有一系列的枚舉值,可以指定求解的選擇策略。
    var db = solver.MakePhase(shifts_flat, Solver.CHOOSE_FIRST_UNBOUND, Solver.ASSIGN_MIN_VALUE);


    // 創(chuàng)建求解的對象
    var solution = solver.MakeAssignment();
    solution.Add(shifts_flat);
    var collector = solver.MakeAllSolutionCollector(solution);

    solver.Solve(db, new[] { collector });
    Console.WriteLine("Solutions found: {0}", collector.SolutionCount());
    Console.WriteLine("Time: {0}ms", solver.WallTime());
    Console.WriteLine();

    // 顯示一些隨機(jī)的結(jié)果
    var a_few_solutions = new[] { 340, 2672, 7054 };

    foreach (var sol in a_few_solutions)
    {
        Console.WriteLine("Solution number {0}", sol);

        foreach (var i in Enumerable.Range(0, num_days))
        {
            Console.WriteLine("Day {0}", i);
            foreach (var j in Enumerable.Range(0, num_nurses))
            {
                Console.WriteLine("Nurse {0} assigned to task {1}", j, collector.Value(sol, shifts[(j, i)]));
            }
            Console.WriteLine();
        }
    }
}

}
復(fù)制代碼

http://www.cnblogs.com/BeanHsiang/p/8663625.html

總結(jié)

以上是生活随笔為你收集整理的C# 解决组合优化问题的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。

主站蜘蛛池模板: 国产一线二线三线女 | 日本肉体xxxx裸体xxx免费 | 99资源| 成人av在线影院 | 国产999精品久久久久久 | 久草综合网 | 亚洲最大成人网色 | 香蕉视频在线观看www | 日韩av手机在线观看 | 天天干狠狠插 | 日本成人在线免费 | 免费人成在线观看 | 瑟瑟视频在线免费观看 | 亚洲欧美乱综合图片区小说区 | 亚洲在线国产 | 女生下面流水视频 | 亚洲女优视频 | 国产精品性爱在线 | 亚洲成人生活片 | 精品国产乱码久久久久久88av | 97在线观看视频 | 国产精品丝袜一区二区 | 97精品久久久 | 伦理欧美 | 美女又爽又黄又免费 | 岛国av网址 | 国产日韩欧美电影 | japanese国产| 好吊色网站 | 亚洲成人av一区二区三区 | 色噜噜成人 | 18岁毛片| 无码一区二区三区免费 | 国精产品一品二品国精品69xx | 图片区 小说区 区 亚洲五月 | 在线播放成人 | 日本三级一区二区 | 天天摸天天操天天射 | 久草视频免费播放 | 九九久久免费视频 | 美女洗澡无遮挡 | 寡妇高潮一级视频免费看 | 天天躁日日躁狠狠躁欧美 | 久久免费视频观看 | 少妇精品无码一区二区三区 | 色噜噜狠狠一区二区三区果冻 | a级无遮挡超级高清-在线观看 | 神马影院午夜伦理片 | 久久久久久久久亚洲 | 少妇一级淫片aaaaaaa | 国产精品久久久久久久久久久久久久久 | 又色又爽又黄18网站 | 欧美日本成人 | 国产视频二区三区 | av鲁丝一区鲁丝二区鲁丝三区 | 亚洲区欧美区 | 欧美一线天 | 看片网址国产福利av中文字幕 | 欧美精品h | 欧美视频一 | 欧美bbbbb性bbbbb视频 | 性xxxx视频播放免费 | 成人国产精品免费观看 | 国产农村妇女精品一区二区 | 天天操天天爽天天射 | 理论片亚洲 | 一区二区三区不卡视频 | 免费高清欧美大片在线观看 | 狠狠人妻久久久久久综合蜜桃 | 日韩精品av一区二区三区 | 爱爱视频日本 | 美女操出白浆 | 黄色aaa视频 | 免费网站在线高清观看 | 日韩欧美久久精品 | 日韩在线视频网站 | 狠狠干2024 | 欧美亚洲一级片 | 国产碰碰 | 国产精品免费大片 | 精品在线视频免费 | 日日舔夜夜操 | 精品91视频 | 天操夜夜操 | 免费在线看黄色片 | 97人妻人人澡人人爽人人精品 | 小日子的在线观看免费第8集 | 欧美特黄| 久久香蕉网站 | 国产激情一区 | 欧美成人短视频 | 欧美一区二区视频在线观看 | 色婷婷久久久 | 黄色片在线视频 | 久久精品韩国 | 91大奶 | 国产亚洲欧美日韩精品一区二区三区 | 国产一区二区三区影视 | 少妇福利视频 |