PAT--關鍵活動(30)
阿新 • • 發佈:2019-01-14
題目太長了,先略去。
還是拓撲排序,建議先了解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; }