万妖瞬击

389 篇文章 1 订阅
8 篇文章 0 订阅

万妖瞬击
Case Time Limit: 2000 MS (Others) / 4000 MS (Java) Case Memory Limit: 256 MB (Others) / 512 MB (Java)
Accepted: 64 Total Submission: 335
查看我的提交显示标签
Problem Description
“万妖穴中有若干小穴,每处小穴中皆有一只恶妖。小穴外设有封印,汝需消灭指定几处小穴中的恶妖方能解除该小穴封印,进而消灭穴中恶妖。”
“此处石壁所刻便是万妖穴中各穴的封印解除关系。”
“吾将瞬雷之法授于汝,汝消灭万妖穴中任一小穴皆仅需一瞬,愿汝尽快消灭各穴恶妖。”
“然消灭小穴后,其对下一处小穴的封印加强通道仍需若干时间方能闭上。”
“万妖穴中气息诡谲,恐有恶灵干扰,将使此段通道关闭时间变长。”
“汝需施法避免几处关键通道免于干扰,以使消灭整个万妖穴的时间免于延长。”
“万妖穴中或有部分小穴未设封印,汝可以此作为突破口。”
“吾将根据石壁所示,将各穴消灭顺序给予汝,汝自珍重。”
Input
每个输入文件中一组数据。
第一行两个正整数N、M(1<=N<=1000,0<=M<=N*(N-1)),表示万妖穴中小穴的个数及封印解除关系的条数。
接下来M行,每行三个整数a、b、c(0 <= a < N, 0 <= b < N, 0 < c <= 20),表示小穴b封印的解除依赖于消灭小穴a中的恶妖,且消灭小穴a中的恶妖后需要时长c才能关闭其对小穴b的封印加强通道(注意,必须将小穴b依赖的所有小穴中的恶妖消灭、并等待针对小穴b的封印加强通道都关闭后才能消灭小穴b)。假设N处小穴的编号分别是0~N-1。数据保证a不等于b,且每组封印解除关系a b最多出现一次。
Output
如果能够消灭所有小穴,那么在第一行输出YES与消灭所有恶妖的总时长,中间用一个空格隔开。然后从第二行开始输出关键路径,格式为用->连接的小穴编号。所谓关键路径是指,此路径上的所有通道的关闭时间均不可以被延长,否则会使消灭所有恶妖的时间变长;且关键路径上所有通道的关闭时长之和就是消灭所有恶妖的总时长。如果有多条关键路径,那么每行输出一条。注意,假设有两条关键路径a[1]->a[2]->…->a[k]->a[k+1]->…与b[1]->b[2]->…->b[k]->[k+1]->…,且a[1]==b[1]、a[2]==b[2]、…、a[k]==b[k]、a[k+1]

1、利用top排序,得到最早开始时间
2、通过逆top排序,得到最晚开始时间
3、如果一个顶点的后序的最晚开始时间减去此顶点到后序顶点的活动时间,则这个顶点就是关键节点,
此节点的后序节点也是关键路径上的节点
4、对于多源点,多汇点的,每一个源点判断其入度为0并且其后序节点也在关键路径上,则这个点需要进行遍历
5、从小到大输出,只需要将每一个节点的直接后序关键节点进行一次排序即可。
#define _CRT_SECURE_NO_WARNINGS
#include <algorithm>
#include <iostream>
#include <vector>
#include <stack>
#include <queue>

typedef struct node {
    int v;
    int w;
    node(int _v,int _w) :v(_v), w(_w) {};
}Node;

using namespace std;
const int MaxN = 1010;
vector<Node>G[MaxN];
vector<int> ciriticalNode[MaxN], cripath;
stack<int>TopOrder;
int InDegree[MaxN], OriginInDegree[MaxN];
int ve[MaxN], vl[MaxN];
int N, M;

bool TopSort() {
    queue<int>que;
    for (int i = 0; i < N; ++i) {
        if (!InDegree[i])que.push(i);
    }

    while (que.size()) {
        int u = que.front(); que.pop(); TopOrder.push(u);
        for (int i = 0; i < G[u].size(); ++i) {
            int v = G[u][i].v;
            if (ve[u] + G[u][i].w > ve[v]) {
                ve[v] = ve[u] + G[u][i].w;
            }
            if (--InDegree[v] == 0) {
                que.push(v);
            }
        }
    }

    if (TopOrder.size() == N)return true;
    return false;
}

int CriticalPath() {
    if (TopSort() == false) return -1;
    int MaxL = -1;
    for (int i = 0; i < N; ++i) {
        if (MaxL < ve[i]) MaxL = ve[i];
    }
    fill(vl, vl + N, MaxL);

    while (TopOrder.size()) {
        int u = TopOrder.top(); TopOrder.pop();
        for (int i = 0; i < G[u].size(); ++i) {
            int v = G[u][i].v;
            if (vl[u] > vl[v] - G[u][i].w) {
                vl[u] = vl[v] - G[u][i].w;
            }
        }
    }

    for (int u = 0; u < N; ++u) {
        for (int i = 0; i < G[u].size(); ++i) {
            int v = G[u][i].v;
            if (ve[u] == vl[v] - G[u][i].w) {
                ciriticalNode[u].push_back(v);
            }
        }
    }

    return MaxL;
}

void printPath(int u) {
    cripath.push_back(u);
    if (ciriticalNode[u].size() == 0) {
        for (int i = 0; i < cripath.size(); ++i) {
            cout << cripath[i];
            if (i != cripath.size() - 1) cout << "->";
        }
        cout << endl;
    }
    sort(ciriticalNode[u].begin(), ciriticalNode[u].end());
    for (int i = 0; i < ciriticalNode[u].size(); ++i) printPath(ciriticalNode[u][i]);
    cripath.pop_back();
}


int main() {
#ifdef _DEBUG
    freopen("data.txt", "r+", stdin);
#endif // _DEBUG
    std::ios::sync_with_stdio(false);

    cin >> N >> M;
    for (int i = 0; i < M; ++i) {
        int u, v, w;
        cin >> u >> v >> w;
        G[u].push_back(node(v, w));
        ++InDegree[v];
        ++OriginInDegree[v];
    }

    int criticalTime = CriticalPath();
    if (criticalTime == -1) {
        cout << "NO " << N - TopOrder.size();
    }
    else {
        cout << "YES " << criticalTime << endl;
        for (int u = 0; u < N; ++u) {
            if (OriginInDegree[u] == 0 && ciriticalNode[u].size()) {
                printPath(u);
            }
        }
    }



    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值