E - Easy Compare-and-Set (欧拉路径+dfs+离散化)

 

假设最开始的起点,也就是上文说的c点,用k表示;

1.明确只有在理想是1的时候,才会进行点的传递,所以我们在建图的时候,把理想度为1的加入图中;(这里注意点一共1e5个,边达到了1e9个,这个时候我们就要进行离散化操作)

2.先判断no的情况:

       (1).如果全为0的时候:如果0的点中存在一个起始点是 k的点,那么直接输出no即可

       (2).1构成的图不是欧拉图的时候也输出no

       (3).举个例子(如下)

                  4 1
                 1 1 0
                 1 1 0    起点k是1点,但是还转移到 1点的时候,那么还是0
                 1 1 0
                 1 1 1

3.其余的情况均为yes:

          那么如何输出呢?

      (1)这里我们先输出理想度是0的,与k值不相等的情况,这样理想度是0的只剩余与k值相等的情况了;

      (2)然后进行dfs特判欧拉路径,这里采用的是有向图判断欧拉路径+剪枝的方法,将欧拉路径存到栈中

      (3)我们在对于栈中的路径,边输出便判断他是否转移的时候不是k,如果找到转移的点不是k的情况,我们就把理想度为0的起始点是k的全部输出掉;

      (4)因为要输出yes和no,在第三步还要判断是否找到转移的点是不是k,所以(1),(2),(3)的输出暂时存入队列中。

#include <iostream>
#include <cstdio>
#include <fstream>
#include <algorithm>
#include <cmath>
#include <deque>
#include <vector>
#include <queue>
#include <string>
#include <cstring>
#include <map>
#include <stack>
#include <set>
#include <bitset>
using namespace std;
const int N = 5e5 + 10;
const int INF = 0x3f3f3f3f;
const long long LLINF = 4e18 + 5;
typedef long long LL;
typedef pair<int, int> PII;
#define xx first
#define yy second
#define endl '\n'

struct node
{

    //	bool operator<(const node &a) const
    //	{
    //	}
};
void ClearFloat()
{
    ios_base::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
}

int read()
{
    int ret = 0, f = 1;
    char ch = getchar();
    while ('0' > ch || ch > '9')
    {
        if (ch == '-')
            f = -1;
        ch = getchar();
    }
    while ('0' <= ch && ch <= '9')
    {
        ret = ret * 10 + ch - '0';
        ch = getchar();
    }
    return ret * f;
}
int n, k, idx;
vector<PII> v[N];               // 存初始点->终点和所对应的边
map<int, vector<int>> mp;       // 存理想都为0的起始点和边
int a[N], b[N], c[N], l[N];     // l是剪枝进行的
map<int, int> out, in, LOL, oo; // 统计入度,出度,进行离散化,栈中存的边转移后的点
bool flag;                      // 是不是全为0
queue<int> qe;                  // 暂时存答案
stack<int> sk;                  // 栈存欧拉图
void dfs(int u, int s)//dfs(点和边)
{
    for (int i = l[u]; i < v[u].size(); i = l[u])
    {
        int pp = v[u][i].first;
        if (pp)
        {
            v[u][i].first = 0;//剪枝
            l[u]++;
            dfs(pp, v[u][i].second);
        }
    }
    //初始没有边只有遍历过的才有边
    if (s != 0)
        sk.push(s);
}
int main()
{
    ClearFloat();
    idx = 1;
    cin >> n >> k;
    for (int i = 1; i <= n; i++)
    {
        cin >> a[i] >> b[i] >> c[i];
        // 进行离散化不然坐标高达1e9
        if (!LOL.count(a[i]))
        {
            LOL[a[i]] = idx++;
        }
        if (!LOL.count(b[i]))
        {
            LOL[b[i]] = idx++;
        }
        // 建图
        if (c[i])
        {
            flag = 1;
            v[LOL[a[i]]].push_back({LOL[b[i]], i});
            out[LOL[a[i]]]++; // 出度
            in[LOL[b[i]]]++;  // 入度
            oo[i] = LOL[b[i]];
        }
        // 存理想度为0的边和起始点
        else
            mp[LOL[a[i]]].push_back(i);
    }
    //    全是0
    if (flag == 0)
    {
        // k也要离散后的结果
        k = LOL[k];
        // 判断是不是有等于k值的
        if (mp.count(k))
        {
            cout << "No" << endl;
        }
        // 没有直接输出
        else
        {
            cout << "Yes" << endl;
            for (auto it : mp)
            {
                for (auto u : it.second)
                {
                    cout << u << " ";
                }
            }
        }
    }
    else
    {
        // 离散的k值都没有说明没有起点
        if (!LOL.count(k))
        {
            cout << "No" << endl;
        }
        else
        {
            k = LOL[k];
            int sum1 = 0, sum2 = 0, root = k, s;
            // 判断欧拉路径
            for (int i = 1; i < idx; i++)
            {
                if (in[i] - out[i] > 1 || out[i] - in[i] > 1)
                {
                    cout << "No" << endl;
                    return 0;
                }
                if (out[i] == in[i] + 1) // 起点
                {
                    root = i;
                    s = v[i][0].second;
                    sum1++;
                }
                else if (out[i] == in[i] - 1)
                {
                    sum2++;
                }
            }
            if (sum1 > 1 || sum2 > 1)
            {
                cout << "No" << endl;
                return 0;
            }
            else if (root != k)
            {
                cout << "No" << endl;
                return 0;
            }
            // 把理想度是0但不等于k的输入到队列里
            for (auto it : mp)
            {
                if (it.first != k)
                {
                    for (auto u : it.second)
                    {
                        qe.push(u);
                    }
                }
            }

            int ll = 0;
            //进行欧拉路径操作
            dfs(root, 0);
            //栈中判断第三种no
            while (sk.size())
            {
                qe.push(sk.top());
                if (oo[sk.top()] != k && !ll)
                {
                    ll = 1;
                    for (auto it : mp[k])
                    {
                        qe.push(it);
                    }
                }
                sk.pop();
            }
            //特判第(3)种no的情况
            if (!ll)
            {
                cout << "No" << endl;
            }
            else
            {
                cout << "Yes" << endl;
                while (qe.size())
                {
                    cout << qe.front() << " ";
                    qe.pop();
                }
            }
        }
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值