08-图9 关键活动 (30分)

本文介绍了一种使用拓扑排序算法寻找关键路径的方法。通过建立正向与反向邻接表来计算最早时间和最迟时间,进而确定关键路径。适用于不允许活动延误的场景。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

/*
这题就是拓扑排序找关键路径,按照陈老师所讲的算法,先建立一个正向链接的邻接表,在建立一个反向链接的邻接表
来记录出度与入读,注意关键路径是指决不允许延误的活动D<i, j> = Lt[j] - Et[i] - C<i, j>
*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define Maxn 1005
#define INF -100005
#define M 100005
//建立邻接表所需的结构体
typedef struct AdjNode* AdjList;
struct AdjNode {
    int index;
    int Weight;
    AdjList Next;
};

typedef struct HNode {
    AdjList FirstEdge; 
}List[Maxn];

typedef struct GNode* LGraph;
struct GNode {
    int Nv;
    List Head;
};

typedef struct ENode* Edge;
struct ENode {
    int V1, V2;
    int Weight;
};
//建一个G2用于反向链接邻接表,便于记录出度,方便反向递推求各点的最迟时间
LGraph G2;

void InsertEdge(LGraph G, Edge E) {
    AdjList NewNode;
    NewNode = (AdjList)malloc(sizeof(struct AdjNode));
    NewNode->index = E->V2;
    NewNode->Weight = E->Weight;
    NewNode->Next = G->Head[E->V1].FirstEdge;
    G->Head[E->V1].FirstEdge = NewNode;

    NewNode = (AdjList)malloc(sizeof(struct AdjNode));
    NewNode->index = E->V1;
    NewNode->Weight = E->Weight;
    NewNode->Next = G2->Head[E->V2].FirstEdge;
    G2->Head[E->V2].FirstEdge = NewNode;
}

LGraph CreateLGraph(int n, int m) {
    int v;
    LGraph G = (LGraph)malloc(sizeof(struct GNode));
    Edge E = (Edge)malloc(sizeof(struct ENode));
    G2 = (LGraph)malloc(sizeof(struct GNode));
    G->Nv = n; G2->Nv = n;
    for(v = 1; v <= n; v++)
        { G->Head[v].FirstEdge = NULL; G2->Head[v].FirstEdge = NULL; }
    for(v = 1; v <= m; v++) {
        scanf("%d%d%d", &E->V1, &E->V2, &E->Weight);
        InsertEdge(G, E);
    }
    return G;
}

void TopSort(LGraph G) {
    int Indegree[Maxn], Outdegree[Maxn], ETime[Maxn], LTime[Maxn], cnt = 0, t = INF;
    int Q[Maxn], front, rear;
    int v;
    AdjList w;
    //计算最早时间
    front = rear = 0;
    //初始化入度数
    for(v = 1; v <= G->Nv; v++) {
        ETime[v] = 0;
        Indegree[v] = 0;
    }
    for(v = 1; v <= G->Nv; v++)
        for(w = G->Head[v].FirstEdge; w; w = w->Next)
            ++Indegree[w->index];
    //入度为零的节点入队,并应初始化起始时间为0
    for(v = 1; v <= G->Nv; v++) if(!Indegree[v]) Q[++rear] = v;
    while(rear != front) {
        v = Q[++front];
        cnt++;
        for(w = G->Head[v].FirstEdge; w; w = w->Next) {
            //Et[w] = max(Et[v] + c<i, j>)
            if(ETime[v] + w->Weight > ETime[w->index]) ETime[w->index] = ETime[v] + w->Weight;
            if(--Indegree[w->index] == 0) Q[++rear] = w->index;
        }
    }//printf("%d\n", cnt);  0
    //若多个终点,找最大时间作为整个过程最早时间
    for(v = 1; v <= cnt; v++)
            if(t < ETime[v]) t = ETime[v];
    //计算每个节点最迟时间,注意先将每个终点的最早时间改成计算出的t
    front = rear = 0;
    for(v = 1; v <= G2->Nv; v++) {
        LTime[v] = M;
        Outdegree[v] = 0;
    }
    for(v = 1; v <= G2->Nv; v++) {
        for(w = G2->Head[v].FirstEdge; w; w = w->Next)
            ++Outdegree[w->index];
    }
    for(v = 1; v <= G2->Nv; v++)
        if(!Outdegree[v]) {
            //printf("%d\n", v);
            LTime[v] = t;
            Q[++rear] = v;
        }//for(v = 1; v <= G->Nv; v++) printf("E = %d, L = %d\n", ETime[v], LTime[v]);
    while(rear != front) {
        v = Q[++front];
        for(w = G2->Head[v].FirstEdge; w; w = w->Next) {
            if(--Outdegree[w->index] == 0) Q[++rear] = w->index;
            if(LTime[w->index] > LTime[v] - w->Weight) LTime[w->index] = LTime[v] - w->Weight;
        }
    }//for(v = 1; v <= G->Nv; v++) printf("E = %d, L = %d\n", ETime[v], LTime[v]);
    if(cnt == G->Nv) {
        printf("%d\n", t);
        for(v = 1; v <= cnt; v++)
            for(w = G->Head[v].FirstEdge; w; w = w->Next)
                if(LTime[w->index] - w->Weight == ETime[v]) printf("%d->%d\n", v, w->index);
    }
    else printf("0\n");
}

int main() {
    int n, m;
    LGraph G;
    scanf("%d%d", &n, &m);
    G = CreateLGraph(n, m);
    TopSort(G);
    return 0;
}

//============================================================================== // WARNING!! This file is overwritten by the Block UI Styler while generating // the automation code. Any modifications to this file will be lost after // generating the code again. // // Filename: D:\NXopen\BaiduSyncdisk\studio\jiamiceshi\ui\jiamiceshi.cpp // // This file was generated by the NX Block UI Styler // Created by: MICH-ROG // Version: NX 12 // Date: 08-19-2025 (Format: mm-dd-yyyy) // Time: 14:36 (Format: hh-mm) // //============================================================================== //============================================================================== // Purpose: This TEMPLATE file contains C++ source to guide you in the // construction of your Block application dialog. The generation of your // dialog file (.dlx extension) is the first step towards dialog construction // within NX. You must now create a NX Open application that // utilizes this file (.dlx). // // The information in this file provides you with the following: // // 1. Help on how to load and display your Block UI Styler dialog in NX // using APIs provided in NXOpen.BlockStyler namespace // 2. The empty callback methods (stubs) associated with your dialog items // have also been placed in this file. These empty methods have been // created simply to start you along with your coding requirements. // The method name, argument list and possible return values have already // been provided for you. //============================================================================== //------------------------------------------------------------------------------ //These includes are needed for the following template code //------------------------------------------------------------------------------ #include "jiamiceshi.hpp" // 在jiamiceshi类实现中添加(jiamiceshi.cpp) // 宽字符转窄字符 std::string jiamiceshi::WideToNarrow(const wchar_t* wideStr) { if (!wideStr) return ""; int bufferSize = WideCharToMultiByte(CP_UTF8, 0, wideStr, -1, nullptr, 0, nullptr, nullptr); if (bufferSize == 0) return ""; std::string narrowStr(bufferSize, 0); WideCharToMultiByte(CP_UTF8, 0, wideStr, -1, &narrowStr[0], bufferSize, nullptr, nullptr); return narrowStr; } // 显示宽字符消息 void jiamiceshi::ShowMessage(const wchar_t* message) { if (theUI) { std::string narrowMsg = WideToNarrow(message); theUI->NXMessageBox()->Show("调试信息", NXOpen::NXMessageBox::DialogTypeInformation, narrowMsg.c_str()); } } // 显示窄字符消息 void jiamiceshi::ShowMessage(const char* message) { if (theUI) { theUI->NXMessageBox()->Show("调试信息", NXOpen::NXMessageBox::DialogTypeInformation, message); } } // 修改后的CheckDateLimit函数 bool jiamiceshi::CheckDateLimit() { try { // 从配置文件读取日期 const int limitYear = ConfigReader::GetInt(L"Expiry", L"Year", 2025); const int limitMonth = ConfigReader::GetInt(L"Expiry", L"Month", 9); const int limitDay = ConfigReader::GetInt(L"Expiry", L"Day", 30); // 获取当前系统时间 time_t now = time(0); tm ltm; if (localtime_s(&ltm, &now) != 0) { ShowMessage("获取本地时间失败"); return false; } int currentYear = 1900 + ltm.tm_year; int currentMonth = ltm.tm_mon + 1; int currentDay = ltm.tm_mday; // 显示当前日期和限制日期 wchar_t dateMsg[256]; swprintf_s(dateMsg, L"当前日期: %d-%d-%d\n限制日期: %d-%d-%d", currentYear, currentMonth, currentDay, limitYear, limitMonth, limitDay); ShowMessage(dateMsg); // 比较日期 if (currentYear > limitYear) { ShowMessage(L"功能已过期:当前年份超过限制年份"); return true; } else if (currentYear == limitYear) { if (currentMonth > limitMonth) { ShowMessage(L"功能已过期:当前月份超过限制月份"); return true; } else if (currentMonth == limitMonth) { if (currentDay > limitDay) { ShowMessage(L"功能已过期:当前日期超过限制日期"); return true; } else if (currentDay == limitDay) { ShowMessage(L"当前日期等于限制日期,功能仍可用"); return false; } } } ShowMessage(L"功能未过期"); return false; } catch (...) { ShowMessage("检查日期限制时发生异常"); return false; } } // 修改后的ConfigReader类 class ConfigReader { public: // 获取整数配置值(宽字符版本) static int GetInt(const wchar_t* section, const wchar_t* key, int defaultValue) { wchar_t configPath[MAX_PATH] = { 0 }; // 获取当前DLL路径 HMODULE hModule = GetModuleHandle(NULL); if (hModule) { // 使用宽字符版本API DWORD pathLen = GetModuleFileNameW(hModule, configPath, MAX_PATH); if (pathLen == 0 || pathLen >= MAX_PATH) { // 路径获取失败,使用当前目录 GetCurrentDirectoryW(MAX_PATH, configPath); PathAppendW(configPath, L"config.ini"); } else { // 替换文件名为config.ini wchar_t* lastBackslash = wcsrchr(configPath, L&#39;\\&#39;); if (lastBackslash) { wcscpy_s(lastBackslash + 1, MAX_PATH - (lastBackslash - configPath) - 1, L"config.ini"); } else { wcscat_s(configPath, MAX_PATH, L"\\config.ini"); } } } else { // 模块句柄获取失败 GetCurrentDirectoryW(MAX_PATH, configPath); PathAppendW(configPath, L"config.ini"); } // 显示配置文件路径 jiamiceshi::ShowMessage(L"配置文件路径: "); jiamiceshi::ShowMessage(configPath); // 检查配置文件是否存在 if (!PathFileExistsW(configPath)) { jiamiceshi::ShowMessage(L"配置文件不存在,使用默认值"); return defaultValue; } // 使用宽字符版本API读取INI文件 return GetPrivateProfileIntW(section, key, defaultValue, configPath); } }; using namespace NXOpen; using namespace NXOpen::BlockStyler; //------------------------------------------------------------------------------ // Initialize static variables //------------------------------------------------------------------------------ Session *(jiamiceshi::theSession) = NULL; UI *(jiamiceshi::theUI) = NULL; //------------------------------------------------------------------------------ // Constructor for NX Styler class //------------------------------------------------------------------------------ jiamiceshi::jiamiceshi() { try { // Initialize the NX Open C++ API environment jiamiceshi::theSession = NXOpen::Session::GetSession(); jiamiceshi::theUI = UI::GetUI(); theDlxFileName = "jiamiceshi.dlx"; theDialog = jiamiceshi::theUI->CreateDialog(theDlxFileName); // Registration of callback functions theDialog->AddApplyHandler(make_callback(this, &jiamiceshi::apply_cb)); theDialog->AddOkHandler(make_callback(this, &jiamiceshi::ok_cb)); theDialog->AddUpdateHandler(make_callback(this, &jiamiceshi::update_cb)); theDialog->AddInitializeHandler(make_callback(this, &jiamiceshi::initialize_cb)); theDialog->AddDialogShownHandler(make_callback(this, &jiamiceshi::dialogShown_cb)); } catch(exception& ex) { //---- Enter your exception handling code here ----- throw; } } //------------------------------------------------------------------------------ // Destructor for NX Styler class //------------------------------------------------------------------------------ jiamiceshi::~jiamiceshi() { if (theDialog != NULL) { delete theDialog; theDialog = NULL; } } //------------------------------- DIALOG LAUNCHING --------------------------------- // // Before invoking this application one needs to open any part/empty part in NX // because of the behavior of the blocks. // // Make sure the dlx file is in one of the following locations: // 1.) From where NX session is launched // 2.) $UGII_USER_DIR/application // 3.) For released applications, using UGII_CUSTOM_DIRECTORY_FILE is highly // recommended. This variable is set to a full directory path to a file // containing a list of root directories for all custom applications. // e.g., UGII_CUSTOM_DIRECTORY_FILE=$UGII_BASE_DIR\ugii\menus\custom_dirs.dat // // You can create the dialog using one of the following way: // // 1. USER EXIT // // 1) Create the Shared Library -- Refer "Block UI Styler programmer&#39;s guide" // 2) Invoke the Shared Library through File->Execute->NX Open menu. // //------------------------------------------------------------------------------ extern "C" DllExport void ufusr(char *param, int *retcod, int param_len) { jiamiceshi *thejiamiceshi = NULL; try { thejiamiceshi = new jiamiceshi(); // The following method shows the dialog immediately thejiamiceshi->Show(); } catch(exception& ex) { //---- Enter your exception handling code here ----- jiamiceshi::theUI->NXMessageBox()->Show("Block Styler", NXOpen::NXMessageBox::DialogTypeError, ex.what()); } if(thejiamiceshi != NULL) { delete thejiamiceshi; thejiamiceshi = NULL; } } //------------------------------------------------------------------------------ // This method specifies how a shared image is unloaded from memory // within NX. This method gives you the capability to unload an // internal NX Open application or user exit from NX. Specify any // one of the three constants as a return value to determine the type // of unload to perform: // // // Immediately : unload the library as soon as the automation program has completed // Explicitly : unload the library from the "Unload Shared Image" dialog // AtTermination : unload the library when the NX session terminates // // // NOTE: A program which associates NX Open applications with the menubar // MUST NOT use this option since it will UNLOAD your NX Open application image // from the menubar. //------------------------------------------------------------------------------ extern "C" DllExport int ufusr_ask_unload() { //return (int)Session::LibraryUnloadOptionExplicitly; return (int)Session::LibraryUnloadOptionImmediately; //return (int)Session::LibraryUnloadOptionAtTermination; } //------------------------------------------------------------------------------ // Following method cleanup any housekeeping chores that may be needed. // This method is automatically called by NX. //------------------------------------------------------------------------------ extern "C" DllExport void ufusr_cleanup(void) { try { //---- Enter your callback code here ----- } catch(exception& ex) { //---- Enter your exception handling code here ----- jiamiceshi::theUI->NXMessageBox()->Show("Block Styler", NXOpen::NXMessageBox::DialogTypeError, ex.what()); } } int jiamiceshi::Show() { try { theDialog->Show(); } catch(exception& ex) { //---- Enter your exception handling code here ----- jiamiceshi::theUI->NXMessageBox()->Show("Block Styler", NXOpen::NXMessageBox::DialogTypeError, ex.what()); } return 0; } //------------------------------------------------------------------------------ //---------------------Block UI Styler Callback Functions-------------------------- //------------------------------------------------------------------------------ //------------------------------------------------------------------------------ //Callback Name: initialize_cb //------------------------------------------------------------------------------ void jiamiceshi::initialize_cb() { try { group0 = dynamic_cast<NXOpen::BlockStyler::Group*>(theDialog->TopBlock()->FindBlock("group0")); selection0 = dynamic_cast<NXOpen::BlockStyler::SelectObject*>(theDialog->TopBlock()->FindBlock("selection0")); expression0 = dynamic_cast<NXOpen::BlockStyler::ExpressionBlock*>(theDialog->TopBlock()->FindBlock("expression0")); } catch(exception& ex) { //---- Enter your exception handling code here ----- jiamiceshi::theUI->NXMessageBox()->Show("Block Styler", NXOpen::NXMessageBox::DialogTypeError, ex.what()); } } //------------------------------------------------------------------------------ //Callback Name: dialogShown_cb //This callback is executed just before the dialog launch. Thus any value set //here will take precedence and dialog will be launched showing that value. //------------------------------------------------------------------------------ // 修改对话框显示回调函数 void jiamiceshi::dialogShown_cb() { try { // 在对话框显示时检查日期限制 if (CheckDateLimit()) { // 显示过期消息 theUI->NXMessageBox()->Show("MICH-明:V:jianjian19951231", NXMessageBox::DialogTypeError, "此功能已过期,无法使用!\n请联系开发者获取更新版本。"); // 禁用所有控件 group0->SetEnable(false); // 禁用组 selection0->SetEnable(false); // 禁用选择对象控件 expression0->SetEnable(false); // 禁用表达式控件 // 隐藏确定和应用按钮 PropertyList* okProps = GetBlockProperties("OK"); // 获取OK按钮属性 if (okProps) { okProps->SetLogical("Show", false); // 隐藏确定按钮 } PropertyList* applyProps = GetBlockProperties("Apply"); // 获取应用按钮属性 if (applyProps) { applyProps->SetLogical("Show", false); // 隐藏应用按钮 } } } catch (exception& ex) { // 异常处理 theUI->NXMessageBox()->Show("错误提示:", NXOpen::NXMessageBox::DialogTypeError, ex.what()); } } //------------------------------------------------------------------------------ //Callback Name: apply_cb //------------------------------------------------------------------------------ // 修改应用回调函数 int jiamiceshi::apply_cb() { int errorCode = 0; try { // 检查日期限制 if (CheckDateLimit()) { theUI->NXMessageBox()->Show("MICH-明:V:jianjian19951231", NXMessageBox::DialogTypeError, "此功能已过期,无法执行操作!"); return 1; // 返回错误代码 }//结束日期检查 //---- Enter your callback code here ----- } catch(exception& ex) { //---- Enter your exception handling code here ----- errorCode = 1; jiamiceshi::theUI->NXMessageBox()->Show("Block Styler", NXOpen::NXMessageBox::DialogTypeError, ex.what()); } return errorCode; } //------------------------------------------------------------------------------ //Callback Name: update_cb //------------------------------------------------------------------------------ int jiamiceshi::update_cb(NXOpen::BlockStyler::UIBlock* block) { try { if(block == selection0) { //---------Enter your code here----------- } else if(block == expression0) { //---------Enter your code here----------- } } catch(exception& ex) { //---- Enter your exception handling code here ----- jiamiceshi::theUI->NXMessageBox()->Show("Block Styler", NXOpen::NXMessageBox::DialogTypeError, ex.what()); } return 0; } //------------------------------------------------------------------------------ //Callback Name: ok_cb //------------------------------------------------------------------------------ int jiamiceshi::ok_cb() { int errorCode = 0; try { errorCode = apply_cb(); } catch(exception& ex) { //---- Enter your exception handling code here ----- errorCode = 1; jiamiceshi::theUI->NXMessageBox()->Show("Block Styler", NXOpen::NXMessageBox::DialogTypeError, ex.what()); } return errorCode; } //------------------------------------------------------------------------------ //Function Name: GetBlockProperties //Description: Returns the propertylist of the specified BlockID //------------------------------------------------------------------------------ PropertyList* jiamiceshi::GetBlockProperties(const char *blockID) { return theDialog->GetBlockProperties(blockID); } :报错严重性 代码 说明 项目 文件 行 禁止显示状态 错误(活动) E0265 函数 "jiamiceshi::ShowMessage(const wchar_t *message)" (已声明 所在行数:52) 不可访问 jiamiceshi D:\NXopen\BaiduSyncdisk\studio\jiamiceshi\jiamiceshi.cpp 166 错误(活动) E0265 函数 "jiamiceshi::ShowMessage(const wchar_t *message)" (已声明 所在行数:52) 不可访问 jiamiceshi D:\NXopen\BaiduSyncdisk\studio\jiamiceshi\jiamiceshi.cpp 165 错误(活动) E0265 函数 "jiamiceshi::ShowMessage(const wchar_t *message)" (已声明 所在行数:52) 不可访问 jiamiceshi D:\NXopen\BaiduSyncdisk\studio\jiamiceshi\jiamiceshi.cpp 170
最新发布
08-20
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值