PAT--關鍵活動(30)

題目太長了,先略去。

還是拓撲排序,建議先了解http://blog.csdn.net/grooowing/article/details/45201267

這題主要就是

1,求出活動最早完成時間early[i],

early[i]=max{early[i]+<i,j>};順推。

2,求出活動在不拖延整體工期是最晚完成時間last[i];從後向前推:

last[i]=min{last[j]-<i,j>}//注意是j

3,對於i->j,如果有有向邊,那麼靈活時間就是last[j]-early[i]-<i,j>,如果爲0,則爲關鍵路徑。


詳見代碼,其實

http://blog.csdn.net/grooowing/article/details/45201267

這個如果明白了,這題就不難啦。注意我的“呵呵呵呵呵”,在順推的時候,入度爲0的節點,early初始值應該是0,但逆推的時候,對於出度爲0的節點,last的初值,應該是最大的工期,就是第一個輸出的那個值。


#include<stdio.h>
#define num 100
#include<queue>
#include<algorithm>
using namespace std;

//節點個數,邊數
int N,M;
//bool isin[num];
//入度,出度,每個節點需要花費時間,節點之間關係矩陣
int indgree[num];
int outdegree[num];
int early[num];
int last[num];
int info[num][num];
//初始化,
int hehehe;
void init(){
	int i,j;
	for(i=0;i<num;i++){
		for(j=0;j<num;j++){
			info[i][j]=-1;
		}
		indgree[i]=0;
		outdegree[i]=0;
		last[i]=100000;
		early[i]=0;
	}
}
//求最大值
int max(int x,int y){
	return x>y?x:y;
}

int min(int x,int y){
	return x<y?x:y;
}

typedef struct {
	int i,j;
	int xuhao;
}Node;
Node node[num][num];

bool cmp(Node a,Node b){
	return a.xuhao>b.xuhao;
}

int solve(){
	int n=0;
	int i,front;
	queue<int> Q;
	for(i=0;i<N;i++){
		if(indgree[i]==0){
			//入度爲0的節點入隊。
			Q.push(i);
			//讓其不再是0,否則會影響後面的入隊
			indgree[i]--;
		}
	}
	//Q不空則循環,
	while(!Q.empty()){
		front=Q.front();
		Q.pop();
		n++;//記錄現在有多少節點出隊
		//出隊的都是可以抹掉的節點
		for(i=0;i<N;i++){
			if(info[front][i]>=0){//如果要抹掉的節點與某個節點有一條有向邊,
				//該邊入度減一,計算該邊的cost
				indgree[i]--;
				early[i]=max(early[i],early[front]+info[front][i]);
			}
		}
		//重新尋找需要入隊的
		for(i=0;i<N;i++){
			if(indgree[i]==0){
				Q.push(i);
				indgree[i]--;
			}
		}
	}
	//如果刪掉N個邊說明沒有環,注意cost[front]不是最終結果
	if(n==N)return early[front];
	//否則
	return -1;
}
//從後向前
void solve2(){
	queue<int> Q;
	int i,front;
	for(i=0;i<N;i++){
		if(outdegree[i]==0){
			//出度爲0的節點入隊。
			Q.push(i);
			//初始化
			//last[i]=early[i];
			//呵呵呵呵呵呵呵呵呵
			last[i]=hehehe;
			//讓其不再是0,否則會影響後面的入隊
			
			outdegree[i]--;
		}
	}
	while(!Q.empty()){
		front=Q.front();
		Q.pop();
		//出隊的都是可以抹掉的節點
		for(i=0;i<N;i++){
			if(info[i][front]>=0){//如果某個節點與要抹掉的節點有一條有向邊,
				//該邊出度減一,計算該邊的last
				outdegree[i]--;
				last[i]=min(last[i],last[front]-info[i][front]);
			}
		}
		//重新尋找需要入隊的
		for(i=0;i<N;i++){
			if(outdegree[i]==0){
				Q.push(i);
				outdegree[i]--;
			}
		}
	}

}
int main(){
	int file=0;
	FILE* fp;
	init();
	int i,temp1,temp2,temp3;
	if(file){
		
		fp=fopen("3.txt","r");
		if(fp==NULL){
			puts("ERROR!");
		}
		fscanf(fp,"%d%d",&N,&M);
		for(i=0;i<M;i++){
			fscanf(fp,"%d%d%d",&temp1,&temp2,&temp3);
			
			info[temp1-1][temp2-1]=temp3;
			indgree[temp2-1]++;
			outdegree[temp1-1]++;
			node[temp1-1][temp2-1].xuhao=i;
			//printf("%d,%d,%d\n",temp1,temp2,info[temp1][temp2]);
		}
	}
	else{
		scanf("%d%d",&N,&M);
		for(i=0;i<M;i++){
			scanf("%d%d%d",&temp1,&temp2,&temp3);
			//注意序號從0開始
			info[temp1-1][temp2-1]=temp3;
			indgree[temp2-1]++;
			outdegree[temp1-1]++;
			//排序用
			node[temp1-1][temp2-1].xuhao=i;
		}
	}
	int res=solve();
	if(res==-1){
		puts("0");
		return 0;
	}
	else{
		for(i=0;i<N;i++){
			//可能有多個終點,需要找到耗時最多的那個
			res=max(early[i],res);
			//printf("%d,",early[i]);
		}
		printf("%d\n",res);
		hehehe=res;
		solve2();
		int j;
		Node nn[num];
		int s=0;
		for(i=0;i<N;i++){
			s=0;
			for(j=0;j<N;j++){
				if(info[i][j]>=0){
					if(last[j]-early[i]-info[i][j]==0){
						//printf("%d->%d\n",i+1,j+1);
						nn[s].i=i;
						nn[s].j=j;
						nn[s++].xuhao=node[i][j].xuhao;

					}
				}
			}
			//按輸入相反次序排序
			sort(nn,nn+s,cmp);
			for(j=0;j<s;j++){
				printf("%d->%d\n",nn[j].i+1,nn[j].j+1);
			}

		}
	}
	return 0;
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章