Theo quy định về hạch toán kinh tế, chi phí trực tiếp của một công trình bao gồm: - Mua sắm nguyên vật liệu, thiết bị xây lắp công trình
- Chi phí cho thuê máy móc thi công - Chi phí tiền lương cho công nhân
Khác với chi phí gián tiếp, chi phí trực tiếp tăng khi thời gian giảm và khi thời gian vượt quá giới hạn của thời gian bình thường thì chi phí trực tiếp cũng tăng khi thời gian tăng.
Đồ thị chi phí trực tiếp là một đường cong bậc hai có cực tiểu taị điểm bình thường. Trong thực tế thường không có đủ số liệu, nên đường cong biểu diễn mối quan hệ thời gian và giá thành thường lấy gần đúng là một đường thẳng.
Hình 2.6. Đồ thị chi phí trực tiếp
Cách thể hiện đơn giản của mối quan hệ giữa thời gian thực hiện công việc và chi phí trực tiếp có thể thấy ở đồ thị Hình 2.6. Nếu chỉ xét công việc một cách
Chi phí C c C D d D Thời gian
độc lập không nói đến ngày hoàn thành dự án với người quản lý chắc chắn lựa chọn thời gian sao cho chi phí trực tiếp là nhỏ nhất, chúng được thể hiện Dij và Cij (như hình vẽ). Nếu mỗi công việc được lên kế hoạch cho thời gian hoàn thành thì sẽ đạt được chi phí nhỏ nhất theo cách đó, thời gian để hoàn thành toàn bộ dự án có thể sẽ kéo dài và các mốc thời gian quan trọng có thể bị ảnh hưởng do khởi công muộn của dự án bị mắc phải.
Ở mức độ cao nhất, người quản lý có thể chọn lựa cách hoàn thành công việc với thời hạn nhỏ nhất có thể, c
ij
D , nhưng đồng thời với chi phí cao nhất c ij
C . Đây chính là thời gian hoàn thành nhỏ nhất thông thường người ta gọi là “công việc bị dồn thời gian” hay “công việc nước rút”. Mỗi quan hệ tuyến tính của chúng được thể hiện trên đồ thị giữa các điểm này có ý nghĩa là bất kỳ khoảng thời gian hoàn thành công việc dij cũng có thể được lựa chọn. Và cũng có thể những điểm đó lại là tối ưu giữa thời gian và chi phí cho các công việc.
Khi đó chi phí trực tiếp cho công việc i-j được tính bằng công thức: ) ( ij ij ij ij ij C R D d c
Trong đó, và dij thể hiện khoảng thời gian và chi phí cuối cùng được lập ra cho mỗi công việc i-j. Khoảng thời gian thực tế cho mỗi công việc cần nằm trong khoảng giữa thời gian với chi phí nhỏ nhất (Dij) và thời gian tối thiểu để hoàn thành công việc i-j ( c
ij
D ).
Khi đó chi phí trực tiếp tổng cộng được tính như sau: )) ( ( 1 , , 1 j i i j ij ij ij ij ij tt c C R D d C 2.3.3.3. Giá thành toàn bộ dự án
Sau khi xác định được chi phí trực tiếp tổng cộng (Ctt) và chi phí gián tiếp (
gt
C ), chúng ta có thể xác định được giá thành toàn bộ dự án (C). C = Ctt Cgt
ij
Mục đích của việc phân tích giá thành và thời gian là đi tìm một giá thành nhỏ nhất (Cm in) của dự án tương ứng với thời gian tối ưu (topt). Khi đã xác định được đồ thị giá thành tổng cộng của dự án, thì vấn đề tìm thời gian tối ưu không khó khăn nữa. Việc xác định giá thành tổng cộng bây giờ chuyển thành bài toán xác định chi phí trực tiếp. Như vậy không có nghĩa là chi phí gián tiếp không quan trọng hay dễ dàng xác định, nhưng nó ít ảnh hưởng tới bài toán chúng ta đang xét.
2.3.4. Cân đối giá thành
Một trong những thông số quan trọng trong quản lý dựán là giá thành của dựán. Người quản lý mong muốn dựán hoàn thành sớm nhất ví chi phí nhỏ nhất. Bài toánđặt ra là khi muốn rút ngắn thời gian hoàn thành dựán thì chi phí tăng lên là nhỏ nhất. Đây là một bài toán lớn và có nhiều hướng giải quyết khác nhau:
Phương pháp 1: Sử dụng sơđồ mạng, phương pháp này thực hiện theo 4
bước sau:
Bước 1: Lập sơđồ PERT tìmđường găng và các công việc trên đường găng. Bước 2: Tính chi phí cho việc rút ngắn từng công việc theo từngđơn vị thời gian (hệ số giá thànhRij).
Bước 3: Chọn công việc trên đường găng có hệ số giá thành nhỏ nhất và rút ngắn tốiđa công việc này nếu có thể hoặc rút ngắn thời gian hoàn thành công việc đến mục tiêu đãđịnh.
Bước 4: Kiểm tra lạiđường găng mà ta đã rút ngắn có còn làđường găng không. Nếu nó vẫn làđường găng thì quay về bước 3, ngược lại, tìmđường găng khác rồi quay lại bước 3. Lặp lại bước 3 - 4 đến khi đạt mục tiêu rút ngắn cho trước.
Ví dụ. Cho một sơ đồ mạng sự kiện hình 2.7 và các chỉ tiêu được liệt kê ở bảng 2.2 dưới đây.
Bảng 2.2. Bảng các công việc và thông số về thời gian và chi phí
Công việc Cij Dij c ij C Dijc Rij A 8 6 14 4 3 B 4 1 4 1 --- C 8 8 24 4 4 D 10 5 24 3 7 E 10 9 18 5 2 F 20 12 36 6 2.7 G 10 3 18 2 8
Hình 2.7. Rút ngắn thời gian bằng phương pháp sơ đồ mạng
Đơn vị tính: 1000$ Trong sơđồ mạng, theo các các thông số tínhđược thì thời gian hoàn thành dựán là 32 ngày, tổng chi phí bình thường là 70.
Sơđồ có mộtđường găng: C, X, E, F, G. Tiến hành rút ngắn thời gian hoàn thành dựán: trên đường găng C, X, E, F, G, công việc E có hệ số giá thành nhỏ nhất là 2, chúng ta thực hiện rút ngắn công việc này từ 9 ngày, xuống còn 5 ngày (thời gian giới hạn). Khi đó chi phí tăng lên: (9 – 5) * 2 = 8. Do đó chi phí toàn phần là 78 và thời gian hoàn thành dựán là 28. Kết quảđược thể hiện trên hình 2.8 sau:
Hình 2.8. Sơ đồ mạng sau khi rút ngắn công việc E.
Sau khi rút ngắn công việc E, có hai đường găng: C, X, E, F, G và C, D, F, G. Tiếp tục rút ngắn thời gian của dự án, ta thấy công việc E tuy có hệ số giá thành nhỏ nhất nhưng sẽ không thể giảm thời gian thực hiện được nữa, đồng thời ta
6 2929 3 8 8 5 17 7 32 32 1 0 0 B X A 2 6 7 F D E G C 4 88 6 2525 3 8 8 5 13 13 7 28 28 1 0 0 B X A 2 6 7 F D E G C 4 88
thấy công việc F nằm trên cả 2 đường găng, và cũng có hệ số giá thành nhỏ nhất. Khi giảm thời gian thực hiện công việc F này từ 12 ngày xuống 6 ngày, sẽ làm cho chi phí tăng 16, nhưng vẫn không làm thay đổi đường găng, đồng thời thời gian thực hiện dự án lại rút ngắn thêm được 6 ngày nữa còn 22 ngày. Công việc tiếp theo có thể thay đổi là công việc C, nếu ta tiến hành giảm thời gian thực hiện công việc C xuống 1 ngày, sẽ làm tăng chi phí thêm 4, nhưng đồng thời cũng làm cho công việc A và B trở thành công việc găng. Và thời gian của dự án lúc này là 21 ngày.
Bây giờ nếu tiếp tục muốn rút ngắn thời gian xuống còn 20 ngày, ta sẽ phải lựa chọn xem nên rút ngắn công việc nào là thích hợp. Nếu ta chọn công việc G để rút ngắn thì chi phí tăng lên là 8. Mặt khác ta thấy nếu công việc A đi thì chi phí sẽ tăng lên là 3, đồng thời C là việc găng có cùng sự kiện đầu với A nên cũng phải giảm công việc C. Chính vì thế chi phí thực sự sẽ tăng nếu giảm A và C là 3+4 =7<8. Nên trong trường hợp này, phương án được chọn là giảm công việc A và C, thay vì giảm công việc G.
Tiếp tục làm như vậy, chú ý tới thời gian giới hạn của các công việc chúng ta sẽ thu được chi phí của dự án tương ứng với sự giảm thời gian của dự án.
Phương pháp 2:Sử dụng quy hoạch tuyến tính (Project Crashing with Linear
Programing).
Chúng ta cần tính thời gian rút ngắn của từng công việc sao cho tổng chi phí của dựán là nhỏ nhất, tức là ta phải tìm giá trị nhỏ nhất của z, với:
)) ( ( 1 , , 1 j i i j ij ij ij ij ij C R D d c z
Với các ràng buộc sau: 1) c ij ij
ij d D
D , với mọi công việc (i-j), điều kiệnđểđảm bảo thời gian thực hiện không vượt quá cho phép.
2) x(i)dij x(j),x(1)0,i1n, với x(i) là thời gian sớm nhấtđể hoàn thành sự kiện i, điều kiện nàyđểđảm bảo cấu trúc trước sau của các sự kiện và các công việc trong sơđồ mạng.
Bằng máy vi tính và các phần mềm giải các bài toán quy hoạch tuyến tính chúng ta dễ dàng tìm ra phương án tốiưu của bài toán.
Sau đây, chúng tôi triển khai thuật toánđể giải bài toán bằng phương pháp sơđồ mạng trong mục 2.3.6.
2.3.5. Thuật toán tối ưu chi phí và giá thành
Thời gian và chi phí có mối quan hệ mật thiết với nhau, đôi khi ta muốn rút ngắn 1 ngày thì chi phí có thể tăng thêm một chút, nhưng có thể rút ngắn 2 ngày thi chi phí lại tăng lên rất nhiều. Như vậy việc quyếtđịnh rút ngắn hay không và rút ngắn bao nhiêu ngày cho phù hợp còn phụ thuộc vàođiều kiện thực tế khi dựán diễn ra. Nếu thời gian hoàn thành dựán rút ngắn so với kế hoạch thì ta phải chịu chi phí vượt trội. Thuật toán dựa vào thông số hệ số giá thành của các công việc sao cho khi rút ngắn thời gian hoàn thành dựán thì chi phí vượt trộiở mức thấp nhất có thể.
Nhưđã nêu phương pháp rút ngắn thời gian sử dụng sơđồ mạng trong mục 2.3.5, dướiđây là thuật toán cho bài toán tốiưu chi phí và giá thành:
Thuật toán tối ưu chí phí và giá thành:
Input: mảng công việc T[], ma trận của đồ thị sự kiện B[][], mảng thời gian dự trữ của công việc Dt[];thời gian rút gọn của dự án tg3; chi phí ban đầu của dự án cp1.
Output: mảng công việc T[] chứa các công việc sau khi đã rút gọn, chi phí sau khi rút gọn dự án cp3.
Trong thuật toán này sử dụng 1 mảng cv[] mà mỗi phần tử có cấu trúc như sau:
Struct myCost {
int tt; //số thứ tự của công việc sẽ giảm thời gian
float hs; //Tổng chi phi sẽ tăng thêm nếu giảm thời gian công việc này
int ds[30]; //Danh sách các công việc sẽ bị thay đổi theo
} ;
void Rut_ngan_thoi_gian()
myCost cv[100]; Tính hệ số giá thành
Nhập khoảng thời gian muốn rút ngắn i0 do
{ n=0;
for(k=1;k<=nT;k++)
if((Dt[i]==0)&&(T1[i].tgian>T1[i].tgian))
{//Nếu là việc găng và vẫn có khả năng rút ngắn được
n++;
cv[n].tt =k; cv[n].hs=hs[k]; cv[n].ds[0]=0;
if(kqcount>1)//Co nhieu hon 1 duong gang
{Lấy sự kiện đầu của công việc k đưa vào biến h Lấy sự kiện cuối của công việc k đưa vào biến c
Tính số công việc có cùng sự kiện đầu với k đưa vào biến dh Tính số công việc có cùng sự kiện cuối với k đưa vào biên dc
d=0;
if(dh>1) //Có nhiều hơn 1 công việc có cùng sự kiện đầu
{for(j=1;j<=sMax;j++)
{if((B[h][j]!=k)&&(B[h][j]>0)&&(Dt(B[h][i]]==0))
//Công việc thật cùng sự kiện đầu, và là công việc găng
if(T1[B[h][j]].tgianth>T1[B[h][j]].tgiangh) {cv[n].hs=cv[n].hs+hs[B[h][j]];
cv[n].ds[++d]=B[h][j]; }
if[[B[h][j]!=k)&&[B[h][j]==-1))
{//Công việc ảo có cùng sự kiện đầu
//Tiến lên trước sự kiện đó,rồi lại tính tương tự
for[int l=1;l<sMax;l++)
if[[T1[B[j][l]].tgianth>T1[B[j][l]].tgiangh)&&[Dt[B[j][l]==0) {cv[n].hs=cv[n].hs+hs[B[j][l]];
cv[n].ds[++d]=B[j][l]; } //for j
}//if dh>1
if(dc>1)
{Voi cac cong viec co cung su kien cuoi voi cong viec k
làm tương tự như đối với các công việc có cùng sự kiện đầu với k Đối với công việc ảo có cùng sự kiện cuối thì ta lùi lại một sự kiện }
cv.ds[0]=d; }
k=tim_min(cv,n);//trả về chỉ số công việc găng cần giảm trong matran cv
cp3=cp3+cv[k].hs; //tính chi phí tăng thêm
T1[cv[k].tt].tgianth--; //Giảm thời gian của các công việc liên quan
if[cv[k].ds[0]>0)
for[i=1;i<=cv[k].ds[0];i++) T1[cv[k].ds[i]].tgiangh--;
TinhthongsoT(T,s,sMax); //Tính lại các thông số sau khi rút ngắn 1 đơn
vị
//Tim duong gang moi strPath.count = 1; strPath.item[1]=s[sMax].tt; GetPath(strPath,s,sMax); i0--; while(i0>0); }//Rut_ngan_thoi_gian
CHƯƠNG 3. ÁP DỤNG XÂY DỰNG CHO CÁC DỰ ÁN XÂY DỰNG
3.1. Phân tích cấu trúc, thuật toán của chương trình
Thuật toán cho bài toán lập và điều khiển tiến độ
Thuật toán lập và điều khiển tiến độ: Biểu diễn sơ đồ mạng sang sơ đồ ngang.
Để thực hiện được quá trình đưa sơ đồ mạng sang sơ đồ ngang ta triển khai các thuật toán chi tiết như sau:
Thuật toán sắp xếp lại các công việc theo thứ tự topo:
Input: mảng T với nT công việc, ma trận A biểu diễn quan hệ giữa các công việc ban đầu có cỡ nT x nT. Quan hệ giữa các công việc phải không có chu trình.
Output: ma trận A biểu diễn quan hệ giữa các công việc theo trật tự tôpô, mảng Order lưu thứ tự các công việc sau khi đã sắp xếp tôpô.
Void Topo;
{ //tạo mảng Order với thứ tự các công việc theo trật tự topo. k=0; //số đỉnh trọc trong một lần xét.
do{ d=0;
for (i=1;i<=nT; i++)
if (cột(A,i)&&(KT[i]==0)){ k=k+1; d=d+1; Order[k]=i; KT[i]=1; }
if (d==0) break; //lỗi sắp topo có chu trình for (i=d-k+1; i=k;i++)
Xoahang(A,i); //xoá hàng i,cột i trong A. }
while (k==nT);
if (d==0) cout<<”lỗi sắp topo có chu trình”; //xác định lại bảng công việc T theo thứ tự Order T1=T; //lưu mảng T for (i=1;i<=nT;i++) { T[i]=T1[Order[i]]; for (j=1; j<=T[i].truoc[0];j++) for (k=1;k<=i-1;k++) if(T[i].truoc[j]==Order[k]) T[i].truoc[j]=k; T[i].tt=i;
for (j=1; j<=(T[j].truoc[0]-1);j++)
for (k=1; k<=T[i].truoc[0];k++)
if(T[i].truoc[i]>T[i].truoc[k])
Đổichỗ(T[i].truoc[i],T[i].truoc[k]); }
//Tạo lại ma trận A từ bảng công việc T mới
}
Thuật toán chuyển đồ thị biểu diễn công việc sang đồ thị biểu diễn sự kiện
Input : ma trận biểu diễn quan hệ công việc A
Output: ma trận biểu diễn sự kiện B của sơ đồ mạng Trong thuật toán có sử dụng các hàm :
int ladinhket(i,A):Hàm nhận giá trị 1 nếu đỉnh i không có cung đi ra trong đồ thị công việc biểu diễn bằng ma trận A và nhận giá trị 0 nếu ngược lại.
int khongcodinhvao(A,i): Hàm nhận giá trị 1 nếu đỉnh i không có cung đi vào trong đồ thị công việc biểu diễn bằng ma trận A và nhận giá trị 0 nếu ngược lại.
void chuyen() { Khởi tạo mang B=0;
sMax=1; //số sự kiện
for (i=1; I<=nT; I++ )
{if (ladinhket(I,A)==0) tăng thêm 1 đỉnh cho nS;
if (ladinhket(I,A)==1))
{ tăng_thêm_một_đỉnh_cho_nS; }
if (khongcodinhvao(A,i)==0) B[1][nS] = i;
co1dinhvao(A,i,&cout1,&thu1); //tính toán số cung đi vào đỉnh i //trả vào cout1, thu1 lưu giá trị của hàng có 1 phần tử đầu tiên.
if (cout1==1) //chỉ có một cung vào đỉnh i
{for (hang=1; hang<=nS; hang++)
for (cot=1;cot<=nS; cot++)
{/*Tìm nút sự kiện kết thúc công việc trước.
Nối nút sự kiện vừa thêm băng công việc đang xét*/
if(B[hang][cot]==thư1) B[cot][nS] =i; } }
else //cout1 >1 có nhiều cung vào
{
Chọn cung có thứ tự bé nhất;
Xác định công việc trước của cung này trong ma trận A; Tìm_sự kiện kết thúc công việc này trong đồ thị biểu diễn bằng ma trận B;
Nối nút này với sự kiện mới thêm; Đánh số cung này là sự kiện đang xét;
//Các bước trên thực hiện tương tự như trường hợp cout=1
Duyệt tất cả các cung còn lại, tạo một công việc ảo đến sự kiện đã chọn;
} } //end of for
Nếu có nhiều đỉnh kết, ta chọn một trong các đỉnh đó làm đỉnh kết, nối các đỉnh kia với đỉnh được chọn bằng một công việc ảo.
}//end of chuyen
Thuật toán tìm đường găng
Input: Ma trận B[][], mảng sự kiện s[], mảng công việc T[]
Output: các công việc găng ghi trong mảng G[][]
Void Criticalpath;
{ // Tính thời gian sớm của mỗi sự kiện
s[1].tgs=0; s[1].before[0]=1; s1.before1=0;
for (i=2; i<=sMax; i++)
{ d=0;
for (j=1; j<=i-1; j++)
Tìm sự kiện có cung tới i với tổng
s[i].tgs+T[B[i][j]].tgian lớn nhất;
Ghi các sự kiện có tổng s[j].tgs+T[B[i][j]].tgian đạt max vào trường trường before
} //end of i
//tính thời gian muộn của mỗi sự kiện
s[nS].tgm=s[nS].tgs;
for (i=nS-1; i>=1; i++) { for(j=nS; j>=i+1;j++ )
Tìm tgmin=min{ s[j].tgm-T[B[i][j].tgian }của sự kiện j có cung đến i;
s[i].tgm=tgmin; } //end of i
//tính thời gian dự trữ của từng sự kiện
for (i=1; i<=nS; i++)
D[i]=s[i].tgm-s[i].tgs;
//Tìm đường găng
Duyệt các sự kiện có dự trữ D[i]=0 theo các chỉ số ghi trong trường before của từng sự kiện;
Khi được 1 sự kiện thì tăng i;
if ((s[i].before[0]=1) &&(s[i].before[1]=0)) Ghi tất cả các sự kiện đó vào mảng G;
Thuật toán đưa ra mức tài nguyên ban đầu
Input: Mảng công việc T[], mảng sự kiện s[], ma trận B[][] của đồ thị sự kiện.
Output: Mảng Rs[] lưu mức sử dụng tài nguyên trong từng thời điểm và