80分求助,悬赏b站硬币(最高140硬币))
查看原帖
80分求助,悬赏b站硬币(最高140硬币))
297831
idgg007楼主2023/10/14 10:47

记录

/*
 思路:
 对于A多于B,建立B->A的一条dis=1的边
 对于A不少于B,建立B->A的一条dis=0的边
 对于A=B,合并A和B
 然后拓扑排序
 显然对于findRoot(A)==findRoot(B)的情况
 如果边权为1则直接炸,输出-1
 满足:
 DP[edge->to] = max(DP[edge->to],DP[edge->from] + edge->dis)
*/
#include <iostream>
#include <vector>
#include <queue>
#include <list>
#include <map>
using namespace std;
struct Edge
{
    int to, dis;
    Edge *nextEdge;
};
struct Data_Edge
{
    int X, A, B;
};
list<Edge> edges;
vector<Edge *> head;
vector<int> father;
vector<Data_Edge> records;
vector<bool> data_fail;
vector<int> inCnt;
vector<int> DP;
map<pair<int, int>, bool> appear_dis_0;
queue<int> que;
int N, K;
void AddEdge(const int &from, const int &to, const int &dis)
{
    edges.push_back({to, dis, head[from]});
    head[from] = &edges.back();
}
int FindRoot(const int &n)
{
    return father[n] ? father[n] = FindRoot(father[n]) : n;
}
void UnionNode(int x, int y)
{
    x = FindRoot(x);
    y = FindRoot(y);
    if (x != y)
    {
        father[x] = y;
    }
}
void Topology()
{
    while (!que.empty())
    {
        int top = que.front();
        que.pop();
        for (Edge *e = head[top]; e != NULL; e = e->nextEdge)
        {
            DP[e->to] = max(DP[e->to], DP[top] + e->dis);
            inCnt[e->to]--;
            if (inCnt[e->to] == 0)
            {
                que.push(e->to);
            }
        }
    }
}
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    cin >> N >> K;
    DP.assign(N + 2, 0);
    inCnt.assign(N + 1, 0);
    father.assign(N + 1, 0);
    head.assign(N + 1, NULL);
    for (int i = 0, x, a, b; i < K; i++)
    {
        cin >> x >> a >> b;
        if (x == 1)
        {
            UnionNode(a, b); // 合并
        }
        else
        {
            switch (x)
            {
            case 3:
                appear_dis_0[{b, a}] = 1; // A>=B&&B>=A与A==B等效
                break;
            case 5:
                appear_dis_0[{a, b}] = 1;
                break;
            default:
                break;
            }
            records.push_back({x, a, b});
        }
    }
    data_fail.assign(records.size(), 0); // 对于被处理为A==B的边信息进行标记
    for (size_t i = 0; i < records.size(); i++)
    {
        switch (records[i].X)
        {
        case 3:
            if (appear_dis_0[{records[i].A, records[i].B}])
            {
                data_fail[i] = true;
                UnionNode(records[i].A, records[i].B);
            }
            break;
        case 5:
            if (appear_dis_0[{records[i].B, records[i].A}])
            {
                data_fail[i] = true;
                UnionNode(records[i].A, records[i].B);
            }
            break;
        default:
            break;
        }
    }
    for (size_t i = 0; i < records.size(); i++) // 建立边
    {
        if (data_fail[i] == 0)
        {
            switch (records[i].X)
            {
            case 2:
            {
                int root_a = FindRoot(records[i].A);
                int root_b = FindRoot(records[i].B);
                if (root_a == root_b) // 对于缩后的点内部边的处理
                {
                    cout << -1;
                    return 0;
                }
                AddEdge(root_a, root_b, 1);
                inCnt[root_b]++;
                break;
            }
            case 3:
            {
                int root_a = FindRoot(records[i].A);
                int root_b = FindRoot(records[i].B);
                if (root_a == root_b) // 对于缩后的点内部边的处理
                {
                    break;
                }
                AddEdge(root_b, root_a, 0);
                inCnt[root_a]++;
                break;
            }
            case 4:
            {
                int root_a = FindRoot(records[i].A);
                int root_b = FindRoot(records[i].B);
                if (root_a == root_b) // 对于缩后的点内部边的处理
                {
                    cout << -1;
                    return 0;
                }
                AddEdge(root_b, root_a, 1);
                inCnt[root_a]++;
                break;
            }
            case 5:
            {
                int root_a = FindRoot(records[i].A);
                int root_b = FindRoot(records[i].B);
                if (root_a == root_b) // 对于缩后的点内部边的处理
                {
                    break;
                }
                AddEdge(root_a, root_b, 0);
                inCnt[root_b]++;
                break;
            }
            default:
                break;
            }
        }
    }
    for (int i = 1; i <= N; i++)
    {
        if (father[i] == 0 && inCnt[i] == 0)
        {
            que.push(i);
            DP[i] = 1;
        }
    }
    Topology(); // Topology排序
    int Ans = 0;
    for (int i = 1; i <= N; i++)
    {
        Ans += DP[FindRoot(i)];
        if (father[i] == 0 && DP[i] == 0)
        {
            cout << -1; //拓扑排序中环不会被访问
            return 0;
        }
    }
    cout << Ans;
    return 0;
}

2023/10/14 10:47
加载中...