K: LED-led Paths (2019湖南ACM多校第5场)

5 篇文章 0 订阅

K: LED-led Paths (2019湖南ACM多校第5场)

Description

In a large city there are n junctions and m one-way streets connecting those junctions. It is known that one can’t walk along the streets infinitely, as there is no directed cycle of streets in the city.

The tourism department has decided to install colored illumination using the LED (light-emitting diode) technology. Each street is to be illuminated with either red ®, green (G), or blue (B) color.

The official city maps for tourists will indicate the selected colors. All continuous paths illuminated by the same color will be suggested for walking and sightseeing. As LEDs will lead people along beautiful ways, these paths will be called LED-led paths.

The health department says that if there is a very long single-color LED-led path, some tourists might overestimate their strength, walk for too long, get too tired, and dislike the city.

Propose a three-color illumination plan in which no single-color LED-led path consists of more than 42 streets.

Input

The first line of the input contains two integers n and m — the number of junctions and streets, respectively (2 ≤ n ≤ 50 000; 1 ≤ m ≤ 200 000).

Each of the following m lines contains two integers ui and vi, denoting a one-way street from junction ui to junction vi (1 ≤ ui, vi ≤ n; ui ≠ vi).

The given city is guaranteed to be acyclic. Each pair of junctions is connected by at most one street.

Output

For each street, in the order of input, output its color on a separate line — a single letter R, G, or B.

Sample Input

5 6
5 3
3 1
1 2
2 4
5 2
3 4

Sample Output

B
R
G
R
B
G
Hint

在这里插入图片描述
 In this example, all single-color LED-led paths are not longer than one street (and therefore not longer than 42 streets), which is absolutely OK according to the health department.

 比赛时,看到题面,直接就dfs搜索,由于有spj,只需要相邻的边不同色就可以保证解决问题。可是dfs到一半,灵机一定,一拍脑袋想到一种新方法(WA自动机)。

WA自动机思路

 新的想法是,将所有节点42个分为一个小组,然后每42个小组又组成一个大组里,考虑到一个小组内只有42个节点,最多只能连成连续的41个边。而一个大组内又只有42个小组。
所以解决策略是:
对于每个访问的边:
如果两个节点在同一个小组中,则上颜色1,(即节点之间颜色1)
如果不在同一个小组,但在同一个大组的话,则上颜色2,(即小组之间颜色2)
否则跨大组,上颜色3,(即大组之间颜色3)
理由:节点只有42个一组,最多只能连成连续的41个边。一个大组中也最多只有42个小组,因此小组之间(颜色2)也最多只能41次。由于 42 ∗ 42 ∗ 42 > 50000 42*42*42 > 50000 424242>50000。可以包括所有数据规模,因此大组之间(颜色3)也最多只能41次。
心情十分愉悦,直接提交
在这里插入图片描述
WA自动机成功实现了!
WA了第一次十分不服气,稍作修改之后自然也就有了第二和第三次和无数次。。。。。。。。。
理想状态是:
在这里插入图片描述
而现实是:
在这里插入图片描述
这回算是WA的我彻底死心了
老老实实BFS
C++交了之后顺利AC 但是又发现一个新问题。(最佳题解在文末) 先上代码:

#include<iostream>
using namespace std;
int vertexNum, edgeNum;
int const maxN = 200000 + 5;
int indexOfLastFrom[maxN] = {0};
int toData[maxN] = {0};
int temp[maxN] = {0};
int nxt[maxN] = {0};
int vertexNumTo[maxN] = {0};
bool visited[maxN] = {0};
int totalNum = 0;
char color[] = {'R', 'B', 'G'};

void addEdge(int u, int v) {
    toData[++totalNum] = v;
    nxt[totalNum] = indexOfLastFrom[u];
    indexOfLastFrom[u] = totalNum;
}

void dfs(int currNode, int lastNode) {
    if (currNode < 0)
        return;
    visited[currNode] = true;
    for (int p = indexOfLastFrom[currNode]; p > 0; p = nxt[p]) {
        if (temp[p] == 0)
            temp[p] = (temp[lastNode] % 3) + 1;
        if (!visited[toData[p]])
            dfs(toData[p], p);
    }
}
int findRoot() {
    int firstNode = 1;
    for (int i = vertexNum; i >= 1; --i) {
        //if no edge to
        if (vertexNumTo[i] == 0) {
            firstNode = i;
            break;
        }
    }
    return firstNode;
}
int main() {
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    cin >> vertexNum;
    cin >> edgeNum;
    for (int i = 0; i < edgeNum; ++i) {
        int a, b;
        cin >> a >> b;
        addEdge(a, b);
        ++vertexNumTo[b];
    }
    int firstNode = findRoot();
    temp[0] = 0;
    dfs(firstNode, 0);
    for (int i = 1; i <= edgeNum; ++i)
        cout << color[temp[i] - 1] << "\n";
    cout << endl;
}

赛后遇到的新问题则是,改为java实现则会RE(和c++的实现完全一致!)
有越界异常 java.lang.ArrayIndexOutOfBoundsException: -1
在这里插入图片描述
我寻思着这哪里可能有会越界到-1啊,命名各个数组都不存在负数。
在这里插入图片描述
把代码中所有要访问数组的地方都加了个if判断后,依然能报这个异常,我也不知道为什么这么神奇
改了许久无果后决定放弃搞这个数组越界问题,直接加上try catch

try {
     myDFS(firstNode, 0);
 } catch (ArrayIndexOutOfBoundsException error) {
     System.out.println("fist Node " + firstNode);
     error.printStackTrace();
 }

这波一折腾,这OJ终于不报越界异常了。但我得到的是一个新异常。What the h***
Holy。。
java.lang.StackOverflowError
在这里插入图片描述
明明和c++实现一致,改成java不是out of bound 就是overflow。。这也太恐怖了pa

一气之下!!!!!!!!!!!!!!!!
再来一个catch!

try {
    myDFS(firstNode, 0);
} catch (StackOverflowError|ArrayIndexOutOfBoundsException error) {
    System.out.println("fist Node " + firstNode);
    error.printStackTrace();
}

我以为这会不会出异常了
结果。。
异常换了一个地方。。。
这里又报java.lang.ArrayIndexOutOfBoundsException: -1

for (int i = 1; i <= edgeNum; ++i)
     out.println(color[temp[i] - 1]);

(原因是在更新temp时除了outofbound或者overflow异常后,temp的更新出到问题,保留了初始值0,减一后自然就越界了)
至此我已经丧失耐心
直接将异常的部分改成了随机颜色

for (int i = 1; i <= edgeNum; ++i)
     if (temp[i] - 1 < 0 || temp[i] - 1 >= color.length)
         out.println(color[rd.nextInt(3)]);
     else
         out.println(color[temp[i] - 1]);

居然顺利AC。。。。。。。此时的代码为:

/*
 * Copyright (c) 2019 Ng Kimbing, HNU, All rights reserved. May not be used, modified, or copied without permission.
 * @Author: Ng Kimbing, HNU.
 * @LastModified:2019-04-22 T 14:05:24.662 +08:00
 */

import java.io.*;
import java.util.Random;
import java.util.StringTokenizer;
import static ACMProblems.ACMIO.*; //My IO

public class Main{
    static int vertexNum, edgeNum;
    static int maxN = 200000 + 5;
    static int[] indexOfLastFrom = new int[maxN];
    static int[] toData = new int[maxN];
    static int[] temp = new int[maxN];
    static int[] next = new int[maxN];
    static int[] vertexNumTo = new int[maxN];
    static boolean[] visited = new boolean[maxN];
    static int totalNum = 0;
    private static char color[] = {'R', 'B', 'G'};

    private static void addEdge(int u, int v) {
        toData[++totalNum] = v;
        next[totalNum] = indexOfLastFrom[u];
        indexOfLastFrom[u] = totalNum;
    }

    static void dfs(int currNode, int lastNode) {
        if (currNode < 0)
            return;
        visited[currNode] = true;
        for (int p = indexOfLastFrom[currNode]; p > 0; p = next[p]) {
            if (temp[p] == 0)
                temp[p] = (temp[lastNode] % 3) + 1;
            if (!visited[toData[p]])
                dfs(toData[p], p);
        }
    }

    public static void main(String[] args) throws Exception {
        setStream(System.in);
        vertexNum = nextInt();
        edgeNum = nextInt();
        for (int i = 0; i < edgeNum; ++i) {
            int a, b;
            a = nextInt();
            b = nextInt();
            addEdge(a, b);
            ++vertexNumTo[b];
        }
        int firstNode = findRoot();
        temp[0] = 0;
        try {
            dfs(firstNode, 0);
        } catch (StackOverflowError | ArrayIndexOutOfBoundsException e) {
        }
        Random rd = new Random();
        for (int i = 1; i <= edgeNum; ++i)
            if (temp[i] - 1 < 0 || temp[i] - 1 >= color.length)
                out.println(color[rd.nextInt(3)]);
            else
                out.println(color[temp[i] - 1]);
        out.flush();
    }

    private static int findRoot() {
        int firstNode = 1;
        for (int i = vertexNum; i >= 1; --i) {
            //if no edge to
            if (vertexNumTo[i] == 0) {
                firstNode = i;
                break;
            }
        }
        return firstNode;
    }
}

以上代码纯属练习dfs,并不适合解决此题

最后给大家提供最快的题解

事实上,这题很好办→_→, 只需要几行代码就能AC

public class Main {
    public static void main(String[] args) throws Exception {
        nextInt();
        int edgeNum = nextInt();
        char color[] = {'R', 'B', 'G'};
        Random rd = new Random();
        for (int i = 0; i < edgeNum; ++i)
            out.println(color[rd.nextInt(3)]);
    }
}

耗时主要取决于随机函数 是不是很暴力哈哈!
在这里插入图片描述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值