質問:
エンジニアリング プロジェクトがサブタスクのグループで構成されており、その一部は並行して実行でき、一部は他のサブタスクを完了した後に実行する必要があると仮定します。「タスクのスケジューリング」には、サブタスクのセットと、各サブタスクを実行できるサブタスクのセットが含まれます。
例えば、専攻の全科目の修了と卒業設計は学部が完了すべきプロジェクトとみなすことができ、各科目はサブタスクとみなすことができます。英語と C プログラミングなど、一部のコースは同時に提供でき、どちらを最初に受講する必要があるかという制限はありません。また、C など、連続した依存関係があるため同時に提供できないコースもあります。プログラミングとデータ構造ですが、前者を最初に学ぶ必要があります。
ただし、サブタスクのグループの場合、任意のタスク スケジューリングは実現可能な解決策ではないことに注意してください。たとえば、計画に「サブタスク A はサブタスク B に依存し、サブタスク B はサブタスク C に依存し、サブタスク C はサブタスク A に依存する」がある場合、これら 3 つのタスクのいずれも最初に実行することはできず、これは実行不可能なスキームです。
タスクのスケジューリング問題では、各サブタスクの完了に必要な時間も指定されている場合、プロジェクト全体を完了するのに必要な最短時間を計算できます。これらのサブタスクのうち、一部のタスクが数日遅れても全体の期間には影響しませんが、一部のタスクは時間通りに完了する必要があり、そうしないとプロジェクト全体の期間が遅れてしまいます。この種のタスクは「」と呼ばれます。主要な活動」。
特定のエンジニアリング プロジェクトのタスク スケジュールが実行可能かどうかを判断するプログラムを作成してください。スケジュール スキームが実行可能である場合は、エンジニアリング プロジェクト全体を完了するのに必要な最短時間を計算し、すべての主要なアクティビティを出力してください。
入力形式:
最初の行に 2 つの正の整数 N (≤100) と M を入力します。N はタスクのハンドオーバー ポイント (つまり、相互に依存する 2 つのサブタスクを接続するノードです。たとえば、タスク 1 が完了した後にタスク 2 が開始する場合、次のようになります)。 2 つのタスク間のハンドオーバー ポイントである必要があります)。ハンドオーバー ポイントには 1 N の番号が付けられ、M はサブタスクの数であり、1 Mの連続番号が付けられます。これに M 行が続き、各行にはタスクの開始と完了に関係するハンドオーバーポイントの番号とタスクに必要な時間を表す 3 つの正の整数が表示され、整数はスペースで区切られます。
出力フォーマット:
タスクのスケジュール設定が不可能な場合は 0 を出力します。それ以外の場合は、最初の行はプロジェクト全体を完了するのに必要な時間を出力し、2 行目はすべての主要なアクティビティの出力を開始します。各主要なアクティビティは 1 行を占め、形式に従って出力されます。 「V->W」。V と W はタスクの開始と完了に関係するハンドオーバー ポイントに番号を付けます。キーアクティビティ出力の順序規則は、タスク先頭の引き継ぎポイントの番号が小さい方が優先され、開始番号が同じ場合は入力時のタスクの順序が逆になる。
入力サンプル:
7 8
1 2 4
1 3 3
2 4 5
3 4 3
4 5 1
4 6 6
5 7 5
6 7 2
出力例:
17
1->2
2->4
4->6
6->7
#include<bits/stdc++.h>
#define MAX 205
using namespace std;
struct NODE
{
int in;
int out;
int numto,numfrom;
int to[MAX],from[MAX];
} node[MAX];
struct EDGE
{
int from;
int to;
int num;
int earlytime;
int latetime;
} edge[MAX*MAX];
int m,n;
int vertex_early[MAX],vertex_late[MAX];
int graph[MAX][MAX];
int vertex[MAX];
int edgeinfo[MAX][MAX];
int edgenum=0;
bool cmp(EDGE a,EDGE b)
{
if(a.from==b.from)
{
return a.num>b.num;
}
return a.from<b.from;
}
bool get_vertex_late(int index)
{
fill(vertex_late,vertex_late+MAX,INT_MAX);
vertex_late[index]=vertex_early[index];
queue<int> q;
bool visnode[MAX];
fill(visnode,visnode+MAX,false);
q.push(index);
int x,cnt;
while(!q.empty())
{
x=q.front();
q.pop();
for(int i=0; i<node[x].numfrom; i++)
{
cnt=node[x].from[i];
vertex_late[cnt]=min(vertex_late[x]-graph[cnt][x],vertex_late[cnt]);
if(vertex_late[x]-vertex_early[cnt]==graph[cnt][x])
{
edge[edgenum].from=cnt;
edge[edgenum].to=x;
edge[edgenum].num=edgeinfo[cnt][x];
edgenum++;
if(!visnode[cnt])
{
q.push(cnt);
visnode[cnt]=true;
}
}
}
}
}
bool topsort()
{
queue<int> q;
for(int i=1; i<=n; i++)
{
if(node[i].in==0)
{
q.push(i);
vertex_early[i]=0;
}
}
int x,cnt,num=0,sum=0;
while(!q.empty())
{
x=q.front();
q.pop();
vertex[num++]=x;
sum++;
for(int i=0; i<node[x].numto; i++)
{
cnt=node[x].to[i];
vertex_early[cnt]=max(vertex_early[cnt],vertex_early[x]+graph[x][cnt]);
node[cnt].in--;
if(node[cnt].in==0)
q.push(cnt);
}
}
if(sum!=n)
return false;
int maxn=0,index=0;
for(int i=1; i<=n; i++)
{
if(maxn<vertex_early[i])
{
maxn=vertex_early[i];
index=i;
}
}
cout<<maxn<<endl;
get_vertex_late(index);
return true;
}
void solve()
{
//cout<<edgenum;
sort(edge,edge+edgenum,cmp);
for(int i=0;i<edgenum;i++)
cout<<edge[i].from<<"->"<<edge[i].to<<endl;
}
int main()
{
//freopen("in.txt","r",stdin);
cin>>n>>m;
int a,b,l;
for(int i=0; i<m; i++)
{
cin>>a>>b>>l;
graph[a][b]=l;
node[a].out++;
node[b].in++;
node[a].to[node[a].numto++]=b;
node[b].from[node[b].numfrom++]=a;
edgeinfo[a][b]=i;
}
if(!topsort())
cout<<0<<endl;
else
solve();
}
PTA コードの詳細については、私のブログを参照してください。
ps: コードは参考用です。盗用しないでください。