NP困難問題の整数線形最適化
サイドの制約によっては、クリティカルパス法または(前の回答で提案されているように)動的計画法を使用できる場合があります。しかし、多くのスケジューリング問題は、古典的な旅行セールスマンと同じようにNP困難です---問題で説明しているように、正確なソリューションには、指数関数的な検索時間の最悪のケースがあります。
NP困難な問題には依然として非常に悪い最悪の場合の解決時間がありますが、非常に短い計算で正確な答えを生成することが非常に多いアプローチがあることを知っておくことが重要です(平均的な場合は許容でき、最悪の場合は見られないことがよくあります) 。
このアプローチは、問題を整数変数を使用した線形最適化問題に変換することです。このような問題を効率的に解決できるフリーソフトウェアパッケージ(lp-solveなど)があります。
このアプローチの利点は、許容可能な時間内にNP困難な問題に対する正確な答えが得られる可能性があることです。私はいくつかのプロジェクトでこのアプローチを使用しました。
問題の説明には側面の制約に関する詳細が含まれていないため、メソッドの適用方法について詳しく説明することはできません。
編集/追加:サンプル実装
あなたのケースでこのメソッドを実装する方法についての詳細は次のとおりです(もちろん、私はあなたの実際の問題には当てはまらないかもしれないいくつかの仮定をします---私はあなたの質問からの詳細しか知りません):
10サイクル以下のcycle(t)(t = 1..10)でスケジュールされる50個の命令cmd(i)(i = 1..50)があると仮定します。命令cmd(i)がcycle(t)で実行されるかどうかを示す500個のバイナリ変数v(i、t)(i = 1..50; t = 1..10)を導入します。この基本的な設定により、次の線形制約が与えられます。
v_it integer variables
0<=v_it; v_it<=1; # 1000 constraints: i=1..50; t=1..10
sum(v_it: t=1..10)==1 # 50 constraints: i=1..50
ここで、サイドコンディションを指定する必要があります。演算cmd(1)... cmd(5)が乗算演算であり、正確に2つの乗数があると仮定します。どのサイクルでも、これらの演算のうち最大2つを並行して実行できます。
sum(v_it: i=1..5)<=2 # 10 constraints: t=1..10
リソースごとに、対応する制約を追加する必要があります。
また、操作cmd(7)が操作cmd(2)に依存し、その後に実行する必要があると仮定します。方程式をもう少し面白くするために、それらの間に2サイクルのギャップも必要とします。
sum(t*v(2,t): t=1..10) + 3 <= sum(t*v(7,t): t=1..10) # one constraint
注:sum(t * v(2、t):t = 1..10)は、v(2、t)が1に等しいサイクルtです。
最後に、サイクル数を最小限に抑えたいと思います。私が提案する方法ではかなり大きな数が得られるため、これはやや注意が必要です。各v(i、t)に、時間とともに指数関数的に増加する価格を割り当てます。将来に向けて操作を延期することは、早期に実行するよりもはるかにコストがかかります。
sum(6 ^ t * v(i、t):i = 1..50; t = 1..10)->最小。#1つのターゲット関数
システムに1サイクルを追加すると、すべてをより少ないサイクルに絞るよりもコストがかかるようにするために、5よりも大きい6を選択します。副作用は、プログラムができるだけ早く操作をスケジュールする方法から外れることです。これを回避するには、2段階の最適化を実行します。まず、このターゲット関数を使用して、必要な最小サイクル数を見つけます。次に、別のターゲット関数を使用して同じ問題を再度尋ねます。最初に使用可能なサイクル数を制限し、後の操作に対してより適度な価格ペナルティを課します。あなたはこれで遊んでいなければなりません、私はあなたがアイデアを得たことを望みます。
うまくいけば、バイナリ変数でそのような線形制約としてすべての要件を表現できます。もちろん、特定の問題に対する洞察を活用して、制約や変数を減らす機会はたくさんあります。
次に、問題をlp-solveまたはcplexに渡して、最適な解決策を見つけてもらいます。