PTA 08-圖9 關鍵活動 (30分)


題目地址

https://pta.patest.cn/pta/test/15/exam/4/question/719

 

假定一個工程項目由一組子任務構成,子任務之間有的可以並行執行,有的必須在完成了其它一些子任務后才能執行。“任務調度”包括一組子任務、以及每個子任務可以執行所依賴的子任務集。

比如完成一個專業的所有課程學習和畢業設計可以看成一個本科生要完成的一項工程,各門課程可以看成是子任務。有些課程可以同時開設,比如英語和C程序設計,它們沒有必須先修哪門的約束;有些課程則不可以同時開設,因為它們有先后的依賴關系,比如C程序設計和數據結構兩門課,必須先學習前者。

但是需要注意的是,對一組子任務,並不是任意的任務調度都是一個可行的方案。比如方案中存在“子任務A依賴於子任務B,子任務B依賴於子任務C,子任務C又依賴於子任務A”,那么這三個任務哪個都不能先執行,這就是一個不可行的方案。

任務調度問題中,如果還給出了完成每個子任務需要的時間,則我們可以算出完成整個工程需要的最短時間。在這些子任務中,有些任務即使推遲幾天完成,也不會影響全局的工期;但是有些任務必須准時完成,否則整個項目的工期就要因此延誤,這種任務就叫“關鍵活動”。

請編寫程序判定一個給定的工程項目的任務調度是否可行;如果該調度方案可行,則計算完成整個工程項目需要的最短時間,並輸出所有的關鍵活動。

輸入格式:

輸入第1行給出兩個正整數NN(\le 100100)和MM,其中NN是任務交接點(即銜接相互依賴的兩個子任務的節點,例如:若任務2要在任務1完成后才開始,則兩任務之間必有一個交接點)的數量。交接點按1~NN編號,MM是子任務的數量,依次編號為1~MM。隨后MM行,每行給出了3個正整數,分別是該任務開始和完成涉及的交接點編號以及該任務所需的時間,整數間用空格分隔。

輸出格式:

如果任務調度不可行,則輸出0;否則第1行輸出完成整個工程項目需要的時間,第2行開始輸出所有關鍵活動,每個關鍵活動占一行,按格式“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

/*
該問題主體框架與上一題相似,也是拓撲排序,但是這次求關鍵路徑。
不想用太繁瑣的解法,想盡量照搬上一題的代碼。
提出一個概念——松節點,與該節點相連的所有路徑都【不是】關鍵路徑。規則如下:
1 如果該結點【發出的所有邊】,距離下個結點的開始時間都有富余,那么該節點是松節點。
2 若一個節點發出的所有邊都連到了松節點上,那么該點也是松節點。
3 如果存在多個終點  該節點為終點,且結束時間比最晚的終點要早,那么該終點為松節點。
其中第三條最容易被忽略掉,導致始終不能AC,結果發現添了第三條還是不能AC
另,結果理論上正確,但是題目要求同一節點發出多條路徑時,要按輸入順序逆序輸出。
那么只好再加個計數了

評測結果
時間	結果	得分	題目	編譯器	用時(ms)	內存(MB)	用戶
2017-07-05 18:29	部分正確	26	5-11	gcc	2	1	
測試點結果
測試點	結果	得分/滿分	用時(ms)	內存(MB)
測試點1	答案正確	15/15	2	1
測試點2	答案正確	3/3	2	1
測試點3	答案正確	3/3	1	1
測試點4	答案正確	1/1	1	1
測試點5	答案正確	4/4	1	1
測試點6	答案錯誤	0/4	2	1

最后一個測試點拿不到成績,然而手里沒有數據能測出問題來
給的提示是【最大N,隨機,可行】
然而並不清楚哪出了問題
先這么放着吧
*/
#include<stdio.h>
#define MAXN 120
#define TRUE 1
#define FALSE 0
#define ERROR -1
struct checkpoint{
	int minStratTime;
	int inEdgeCount;
	int finished;
	int loose;
}gCheckpointTable[MAXN];

int gMatrix[MAXN][MAXN];
int gCountInput[MAXN][MAXN]={0};

void InitCheckpointTable()
{
	int i;
	for(i=0;i<MAXN;i++)
	{
		gCheckpointTable[i].minStratTime=0;
		gCheckpointTable[i].inEdgeCount=0;
		gCheckpointTable[i].finished=0;
		gCheckpointTable[i].loose=0;
	}
}
void InitMatrix(N)
{
	int i,j;
	for(i=0;i<N;i++)
		for(j=0;j<N;j++)
			gMatrix[i][j]=ERROR;
}

int FindPoint(N) //返回一個入度為0並且沒被訪問過的點
{
	int i;
	int p=ERROR;
	for(i=0;i<N;i++)
	{
		if(gCheckpointTable[i].inEdgeCount==FALSE && gCheckpointTable[i].finished==FALSE)
			p=i;
	}
	return p;
}

void SetLoosePoint(int N,int maxtime) //找出所有的松節點,但是如果沒有出邊不能算松節點
{
	int i,j;
	int isLoose,count,countEdge,allLoose;
	for(i=0;i<N;i++)
	{
		isLoose=TRUE;
		count=0;
		for(j=0;j<N;j++)
		{
			if(gMatrix[i][j]==ERROR)
				continue;
			count++;
			if(gCheckpointTable[i].minStratTime+gMatrix[i][j]==gCheckpointTable[j].minStratTime)
				isLoose=FALSE;
		}
		if(count!=0)
			gCheckpointTable[i].loose=isLoose;
	}
	
	do
	{
		count=0;
		for(i=0;i<N;i++)
		{
			if(gCheckpointTable[i].loose==TRUE)
				continue;
			allLoose=TRUE;
			countEdge=0;
			for(j=0;j<N;j++)
			{
				if(gMatrix[i][j]==ERROR)
					continue;
				countEdge++;
				if(gCheckpointTable[j].loose==FALSE)
					{
						allLoose=FALSE;
						break;
					}
			}
			if(allLoose==TRUE && countEdge!=0)
			{
				gCheckpointTable[i].loose=TRUE;
//				printf("set %d  loose\n",i+1);
				count++;
			}
			if(countEdge==0 && gCheckpointTable[i].minStratTime<maxtime)
			{
				gCheckpointTable[i].loose=TRUE;
			}
		}
	}
	while(count);
}

int PrintOredr(int N,int i)
{
	int max,maxIDX,j;
	maxIDX=ERROR;
	max=0;
	for(j=0;j<N;j++)
	{
		if(gCountInput[i][j]>max)
		{
			max=gCountInput[i][j];
			maxIDX=j;
		}
	}
	if(maxIDX != ERROR)
		gCountInput[i][maxIDX]=0;

	return maxIDX;
}
void Calc(int N)
{
	int i,j,maxtime,p;
	while( (p=FindPoint(N)) != ERROR ) //如果還能返回入度為0的點 先叫它v1
	{
		gCheckpointTable[p].finished=TRUE; //先設為處理完成
		for(i=0;i<N;i++)//遍歷該點所有發出去的邊,找一個連接到的點v2
		{
			if(gMatrix[p][i]==ERROR)
				continue;
   			//如果被指向的結點v2,最小完成時間小於此節點v1的最小完成時間 加上  v1到v2的耗時,那么更新v2的最小時間
			if(gCheckpointTable[i].minStratTime<gCheckpointTable[p].minStratTime+gMatrix[p][i])
				gCheckpointTable[i].minStratTime = gCheckpointTable[p].minStratTime + gMatrix[p][i];
			gCheckpointTable[i].inEdgeCount--; //將v2的入度減一
		}
	}
	maxtime=0;
	for(i=0;i<N;i++) //考慮到有多終點問題,算完后把所有節點全掃一遍,挑一個結束時間最大的打出來
	{
		if(gCheckpointTable[i].finished==FALSE)
		{
			printf("0");
			return;
		}
		if(gCheckpointTable[i].minStratTime>maxtime)
			maxtime=gCheckpointTable[i].minStratTime;
	}
	printf("%d\n",maxtime);
	SetLoosePoint(N,maxtime);
	for(i=0;i<N;i++)
	{
		while((j=PrintOredr(N,i))!=ERROR)
		{
			if(gCheckpointTable[i].loose==FALSE && gCheckpointTable[j].loose==FALSE && gMatrix[i][j]!=ERROR && gCheckpointTable[j].minStratTime==gCheckpointTable[i].minStratTime+gMatrix[i][j])
				printf("%d->%d\n",i+1,j+1);
		}
	}
}

int main()
{
	int i;
	int N,M;
	int v1,v2,lastingTime,count;
	scanf("%d %d",&N,&M);
	InitMatrix(N);
	InitCheckpointTable();
	count=1;
	for(i=0;i<M;i++)
	{
		scanf("%d %d %d",&v1,&v2,&lastingTime);
		gMatrix[v1-1][v2-1]=lastingTime;
		gCheckpointTable[v2-1].inEdgeCount++;
		gCountInput[v1-1][v2-1]=count++;
	}
	Calc(N);
}

  

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM