1. 程式人生 > >C語言資料結構--相對路徑設計

C語言資料結構--相對路徑設計

#include<stdio.h>
#include<stdlib.h>
#include<iomanip.h>
#include <process.h>

typedef struct node//邊表結點
{
  int adjvex;  //鄰接點編號
  int dut; //弧的資訊
  struct node *next; //下一條弧指標
}edgenode;

typedef struct  //頂點表結點
{
  int projectname;//頂點域
  int id;//頂點的入度資訊
  edgenode *link; //邊表頭指標
}vexnode;

void CreateGraphic(vexnode* Graphicmap,int projectnumber,int activenumber)//建立圖
{
  int begin,end,duttem; //分別代表弧的前節點,尾節點,活動時間
  edgenode *p;//  邊表頭指標
  for(int i=0;i<projectnumber;i++)
  {
    Graphicmap[i].projectname=i;//頂點的命名按0,1,2,3......
    Graphicmap[i].id =0;//頂點的資訊的度數均賦為零
    Graphicmap[i].link =NULL;
  }
  printf("\n");
  printf("請輸入某專案的資訊,並請用整形數字表示(格式:弧頭,弧尾,權值):\n");
  printf("例如:輸入1,2,4   即代表結點1與4之間的活動需要4個時間單位。\n");
  printf("\n");
  for(int k=0;k<activenumber;k++) //activenumber為活動的數目,即弧的條數
  {
    scanf("%d,%d,%d",&begin,&end,&duttem); //請輸入第%d條的起點、終點和權值
    p=(edgenode*)malloc(sizeof(edgenode));//臨時分配儲存空間
    p->adjvex =end-1;//因為是從零開始記的,姑要減一,就是讓終點插入到鄰接表內
    p->dut =duttem; //該弧的活動時間為duttem
    Graphicmap[end-1].id ++;  //入度加一
    p->next =Graphicmap[begin-1].link ;
    Graphicmap[begin-1].link =p;//讓下一個節點作為下一插入節點的前驅節點
  }
}

int SearchMapPath(vexnode* Graphicmap,int projectnumber,int activenumber
,int& totaltime) //求出最大路徑,並打印出關鍵路徑
{
  int i,j,k,m=0;
  int front=-1,rear=-1;
  int* topologystack=(int*)malloc(projectnumber*sizeof(int));//用來儲存拓撲排列
  int* vl=(int*)malloc(projectnumber*sizeof(int));//用來表示在不推遲整個工程的前提下,VJ允許最遲發生的時間
  int* ve=(int*)malloc(projectnumber*sizeof(int));//用來表示Vj最早發生時間
  int* l=(int*)malloc(activenumber*sizeof(int));//用來表示活動Ai最遲完成開始時間
  int* e=(int*)malloc(activenumber*sizeof(int));//表示活動最早開始時間
  edgenode *p;  //邊表頭的指標
  totaltime=0; //存放整個工程的最短時間
  for(i=0;i<projectnumber;i++) ve[i]=0;//先把每個工程的最早發生時間初始化為零
  for(i=0;i<projectnumber;i++)
  {
    if(Graphicmap[i].id==0)
    {
      topologystack[++rear]=i;//讓所有的頭節點入佇列
      m++;  //記錄入佇列的頂點個數
    }
  }
  while(front!=rear)
  {
    front++; //出佇列
    j=topologystack[front]; //拓撲排序的節點依次出佇列
    m++;  //記錄入佇列的節點個數
    p=Graphicmap[j].link ;  //指向頂點指向的下一個頂點
    while(p)
    {
      k=p->adjvex ; // 鄰接點編號
      Graphicmap[k].id --;//讓入度減一,相當於刪除一個入度為零的前驅節點,和相關的弧
      if(ve[j]+p->dut >ve[k])//將最長的路徑賦給VE[K]
      ve[k]=ve[j]+p->dut ;
      if(Graphicmap[k].id ==0)//如果入度為零,則入佇列
      topologystack[++rear]=k;
      p=p->next ; //指向下一個節點
    }

  }
  if(m<projectnumber)//如果有環,則不能遍歷每個節點
  {
    printf("\n本程式所建立的圖有迴路不可計算出關鍵路徑!\n");
    printf("將退出本程式!\n");
    return 0;
  }
  totaltime=ve[projectnumber-1];//最短完成時間即為最後一個節點所累加的時間之和
  for(i=0;i<projectnumber;i++)
    vl[i]=totaltime;
  for(i=projectnumber-2;i>=0;i--)// 用逆拓撲排序來求活動Ai最遲完成開始時間,即從最後一個節點減去最短的時間
  {
    j=topologystack[i];
    p=Graphicmap[j].link ;
    while(p)
    {
      k=p->adjvex ;
      if((vl[k]-p->dut )<vl[j])
      vl[j]=vl[k]-p->dut ;
      p=p->next ;
    }
  }
  i=0;
  printf("\n");
  printf("| 起點 | 終點 | 最早開始時間 | 最遲完成時間 | 差值 | 備註 \n");
  for(j=0;j<projectnumber;j++)
  {
    p=Graphicmap[j].link;
    while(p)
    {
      k=p->adjvex ;
      e[++i]=ve[j];
      l[i]=vl[k]-p->dut;
      printf("| %4d | %4d | %11d  | %11d  | %3d  |",Graphicmap[j].projectname +1,Graphicmap[k].projectname +1,e[i],l[i],l[i]-e[i]);
      if(l[i]==e[i])  //當差值為零時,則為關鍵路徑
      printf(" 關鍵活動 <%2d,%4d>",
      Graphicmap[j].projectname +1,Graphicmap[k].projectname +1);
      printf("\n");
      p=p->next ;
    }
  }
    return 1;

}

void seekkeyroot()//求關鍵路徑的主函式
{
  int projectnumber,activenumber,totaltime=0;
  printf("\n");
  printf("輸入符合標準,歡迎進入求關鍵路徑的系統!\n");
  printf("\n");
  printf("請輸入這個專案的AOE-網的節點數:     ");
  scanf("%d",&projectnumber);
  printf("請輸入這個專案的AOE-網的活動個數:   ");
  scanf("%d",&activenumber);
  vexnode* Graphicmap=(vexnode*)malloc(projectnumber*sizeof(vexnode));
  CreateGraphic(Graphicmap,projectnumber,activenumber);//建立鄰接圖
  SearchMapPath(Graphicmap,projectnumber,activenumber,totaltime);//求出最大路徑,並打印出關鍵路徑
  printf("\n");
  printf("整個工程所用的最短時間為:%d個單位時間\n",totaltime);
  system("pause");
}

int main()
{
  char ch;
  for(;;)
  {
       do
       {
           system("cls");
           printf("☆★☆★☆★☆★☆★☆★☆★☆★☆★☆★☆★☆★☆★☆★☆★☆★☆★☆★☆★                     \n");
           printf("                        歡迎進入求關鍵路徑演算法程式                                               \n");
           printf("☆★☆★☆★☆★☆★☆★☆★☆★☆★☆★☆★☆★☆★☆★☆★☆★☆★☆★☆★                     \n");
           printf("%s","\ns(start)開始輸入工程的節點資料並求出關鍵路徑\n");
           printf("\n");
           printf("%s","e(exit)退出\n");
           printf("\n");
           printf("%s","請輸入選擇:");
           scanf("%c",&ch);
           ch=toupper(ch);
       }while(ch!='S'&&ch!='E');
       switch(ch)
   {
      case'S':
      seekkeyroot();
           break;
      case'E':
           return 1;
     }
    }
}