for循环中将整形数据(%d)fprintf写入文件中,程序运行结果正确,但文件中的数字与运行框输入的数字不相符,文件中前两列数字均为输入数字减去2得到的结果,第三列数字不正确或为65535。
ShortestTime.cpp
#include<stdio.h>
#include<stdlib.h>
#define MAX 105
#define INFINITY 65535
using namespace std;
typedef struct QNode{
int data;
struct QNode* next;
}QNode,LNode,*LinkList;
typedef struct{
QNode* front;
QNode* rear;
}LinkQueue;
```c
//初始化队列
void InitQueue(LinkQueue &Q){
Q.front=Q.rear=(QNode*)malloc(sizeof(QNode)); //头尾均指向头指针
Q.front->next=NULL; //尾部赋空
}
//尾部插入
void EnQueue(LinkQueue &Q,int data){
QNode* p=(QNode*)malloc(sizeof(QNode));
p->data=data;
p->next=NULL;
Q.rear->next=p;
Q.rear=p;
}
//判空
bool IsEmpty(LinkQueue Q){
if(Q.front->next) return false;//非空
else return true;//空
}
//头部删除;注意删除的结点为尾结点时,重新将尾结点指向头结点
void DeQueue(LinkQueue &Q){
if(!IsEmpty(Q)){
Q.front->next=Q.front->next->next;
if(IsEmpty(Q)) Q.rear=Q.front; //删除尾结点,重新将尾结点指向头结点
}
}
//获取队头元素
int GetTop(LinkQueue &Q){
if(!IsEmpty(Q)){
return Q.front->next->data;
}else return -1;
}
```c
/*AOE拓扑排序的综合问题
可求总工期时常和每个任务的机动时间
每一条边代表一个项目;
每一个结点代表一个任务交接点;
1.求各边的最短工期;(从源点出发,令ve(源点)= 0,
按拓扑有序求其余顶点的最早发生时间ve()
2.倒着,求各点最早开始的时间;(从汇点出发,令vl(汇点)=vee(汇点),
按逆拓扑有序求其余顶点的最迟发生时间vl()
3.两者相减得到各任务的机动时间,
按顺序输出机动时间为0的任务即为关键点路径;
(求AOE网中所有活动的差额d(),找出所有 d() = 0的活动,构成关键路径)
*/
//N为子任务交接点(交接点编号为 1~N),M为子任务的数量
int N,M;
//ETime存放完成每个任务所需要的时间
//PTime存放每个任务的机动时间,即准备灵活运用的准备时间
int ETime[MAX][MAX],PTime[MAX][MAX];
//EarliestTime[]存放每个结点任务的最早开始时间(ve)
//LatestTime[]存放每个结点任务的最晚开始时间(vl)
/*若当前结点的最早开始时间 + 完成该任务所需要时间 = 后一个结点的最晚开始时间,
说明该任务的机动时间为 0,即当前任务为关键任务 */
int EarliestTime[MAX]={0},LatestTime[MAX];
int ST,edv; //ST表示最短工期,
//得到列表中最大的元素
int getMax(int arr[]){
int max=0;
for(int i=0;i<N;i++){
if(max<arr[i]){
max=arr[i]; //找到最大值的值
edv=i; //找到最大值的编号
}
}
return max;
}
//计算各任务最早结束时间;并由统计任务数,判断图是否连通
int Earliest(){
//vex表示结点,count记录结点数
int vex,count=0,Indegree[MAX]={0}; //初始化入度为0
LinkQueue Q; //声明队列
InitQueue(Q); //初始化队列
//计算各个结点入度
for(int i=0;i<N;i++){
for(int j=0;j<N;j++){
if(ETime[i][j]!=INFINITY){ //
Indegree[j]++; //入度 +1
}
}
}
//寻找入度为 0的结点 入队
for(int i=0;i<N;i++){
if(Indegree[i]==0){
EnQueue(Q,i); //在队列末尾加入元素 i
}
}
while(!IsEmpty(Q)){ //判断队列是否为空
vex=GetTop(Q); //访问队头元素,即最早被压入队列的第一个元素
DeQueue(Q); //删除队列的第一个元素,注意,并不会返回被弹出元素的值
count++; //记录结点数(结点数+1)
/*遍历堆头结点后面相邻的任务完成结点,若当前结点加任务时间
大于下一个结点的开始时间,更新下一个结点的开始时间为大值;*/
for(int j=0;j<N;j++)
if(ETime[vex][j]!=INFINITY){ //找到vex后面的边
//取最大的完成时间!!
if(EarliestTime[vex]+ETime[vex][j]>EarliestTime[j]){
EarliestTime[j]=EarliestTime[vex]+ETime[vex][j];
}
//将入度-后为0的结点入队;
if(--Indegree[j]==0)
//若该相邻边入度为 0(说明除了前一个结点没有其他结点与之相连),入队
EnQueue(Q,j);
}
}
//最后getmax得到终点的下标和最大值以及用count判断图是否连通。
ST=getMax(EarliestTime); //找到最大元素——即最少总时间
if(count!=N) return 0; //代表图不连通
else return 1;
}// Earlist已算出每个活动的最晚时间
/*由结束顶点idx回推;
计算每个结点的出度,将出度为0的入队;
初始化结束顶点的最早结束时间;
开始循环:
挨个出队,遍历该结点的每一个前驱结点,前一个结点的开始时间取当前节点的开始时间减去前一个任务的花费时间 的最小值,即开始的越早越好;
必须用<=,只<的话只能算一条关键路径,<=才能算出所有的关键路径(错误原因)
除此之外,需要PTime数组计算机动时间,即前一个结点的开始时间+任务时间刚好=当前结点的开始时间,则该任务无机动时间;
最后将删除该点后出度为0的结点入队;
*/
//计算各任务最晚开始时间
void Latest(){
int vex,Outdegree[MAX]={0}; //初始化出度为 0
LinkQueue Q;
InitQueue(Q);
//计算各结点的出度
for(int i=0;i<N;i++){
for(int j=0;j<N;j++){
if(ETime[i][j]!=INFINITY){
Outdegree[i]++; //出度+1
}
}
}
//出度为 0的入队
for(int i=0;i<N;i++){
if(Outdegree[i]==0){
EnQueue(Q,i); //在队列末尾加入元素 i
}
}
//初始化 Latest(各任务最晚开始时间)
for(int i=0;i<N;i++)
LatestTime[i]=INFINITY;
LatestTime[edv]=ST; //idx为最后一个活动的编号;ECT为该点完成的时间
//从后往前推
while(!IsEmpty(Q)){
vex=GetTop(Q);
DeQueue(Q);
for(int j=0;j<N;j++){
if(ETime[j][vex]!=INFINITY){ //找到v前面的结点
if(LatestTime[vex]-ETime[j][vex]<=LatestTime[j]){
//找到最晚开始的时间,即前面的点最早需要开始的时间
//必须用<=,只<的话只能算一条关键路径,<=才能算出所有的关键路径(错误原因)
LatestTime[j]=LatestTime[vex]-ETime[j][vex];
PTime[j][vex]=LatestTime[vex]-EarliestTime[j]-ETime[j][vex];
//PTime为机动时间:即vex的最晚开始时间-(j的最早开始时间+j到vex所花的时间)
//j的最早开始时间+j到vex所花的时间若等于vex的最晚开始时间,则说明
//从j到vex没有机动时间,即j-v是一条可输出的路径
}
if(--Outdegree[j]==0)
EnQueue(Q,j);
}
}
}
}
//输出函数
void Print(){
printf("\n以最短工期完成该工程的关键路径为:\n");
for(int i=0;i<N;i++) //任务开始的交接点编号小者优先
for(int j=N-1;j>=0;j--) //起点编号相同时,与输入时任务的顺序相反。
if(PTime[i][j]==0)
printf("%d->%d\n",i+1,j+1);
}
```c
int main(){
int a,b;
int choice;
FILE *fp;
fp=fopen("ShortestTime.txt","w");
if(fp==NULL){
printf("\nOpen file Fail,close!");
getchar();
exit(1);
}
do{
printf("\n请输入你想进行的操作:\n");
printf("1-计算最短工期\n");
printf("2-退出\n");
scanf("%d",&choice);
switch(choice){
case 1:printf("计算最短工期\n");
printf("请输入事件(顶点)的个数:");
scanf("%d",&N);
printf("请输入活动(弧)的个数:");
scanf("%d",&M);
//初始化拓扑图A以及各边机动值
for(int i=0;i<N;i++)
for(int j=0;j<N;j++)
PTime[i][j]=ETime[i][j]=INFINITY;
//得到拓扑图A
printf("\n请输入两相邻事件(结点)及其完成它们之间活动所需时间(弧的权值)");
printf("\n(输入的结点与结点,结点与权值间用空格隔开!)\n");
//写入文件
fprintf(fp,"事件->事件 活动时间\n");
//fflush(fp);
for(int i=0;i<M;i++){
scanf("%d %d",&a,&b);
scanf("%d",&ETime[--a][--b]); //编号从1开始,保存从0保存
// 输出格式化文本到文件
fprintf(fp," %d -> %d %d\n",a,b,ETime[--a][--b]);
getchar();
}
if(!Earliest())
printf("输入有误!工程项目安排不合理!\n");
else{
printf("\n完成该工程的最短工期为:%d\n",ST);
fprintf(fp,"\n计算得到该工程的最短工期:%d\n",ST);
Latest();
Print();
}
fclose(fp); //关闭文件
break;
case 2: printf("\n退出程序!\n");
exit(0);
break;
default: printf("\n输入错误!");
}
}while(choice!=0);
}
###### 运行结果及报错内容
测试用例:
请输入事件(顶点)的个数:6
请输入活动(弧)的个数:8
请输入两相邻事件(结点)及其完成它们之间活动所需时间(弧的权值)
(输入的结点与结点,结点与权值间用空格隔开!)
**1 2 3
1 3 2
2 4 2
3 4 4
2 5 3
3 6 3
4 6 2
5 6 1**
运行结果为
完成该工程的最短工期为:8
以最短工期完成该工程的关键路径为:
1->3
3->4
4->6
**文件内容错误:(输入内容错误)**
事件(顶点)数: 6
活动(弧)数: 8
**事件->事件 活动时间
-1 -> 0 0
-1 -> 1 0
0 -> 2 2
1 -> 2 65535
1 -> 4 65535
2 -> 4 65535
3 -> 4 65535
0 -> 3 65535**
###### 我的解答思路和尝试过的方法
fprintf(fp," %d -> %d %d\n",a,b,ETime[--a][--b]);
将该写入文件语句改为三句分三次写入数据时
fprintf(fp," %d ",a);
fprintf(fp," %d ",b);
fprintf(fp," %d ",ETime[--a][--b]);
文件中前两列数字变为输入数字减去1,猜测是否为空格或回车键影响写入文件的结果
###### 我想要达到的结果
写入文件的数据为输入正确数据
有可能数据溢出 被取反了。
或者你的数组越界。导致你的数据发生了溢出。
没看明白,首先代码一团绿,其次也没看懂解释