【问题标题】:Printing the Pair of Numbers in desired format以所需格式打印数字对
【发布时间】:2017-01-13 18:26:34
【问题描述】:

给定一对数字,其中每个数字的频率是偶数(两列频率之和)

1 4
1 5
2 3
3 4
2 5

如何将排列修改为一种形式,使每列具有相等的频率计数,这将是两列中数字的总频率的一半,我只允许交换两个列条目。

1 4
5 1
3 2
4 3
2 5

谁能给我一个提示,还要确保所有组件都以图形表示形式连接,如果断开连接打印-1?

编辑:数字在 n 行和两列中。

row1/col1:1
row1/col2:4
row2/col1:1
row2/col2:5

其他的

【问题讨论】:

  • 我正在使用 cpp,我试图计算两个单独数组中两个列中每个数字的出现次数..并试图使值相等,但对于上述情况会出现冲突这种方法
  • 问题似乎不清楚。你能重新表述一下吗?给定的例子是什么意思?
  • @MBo 在这种情况下,每个数字的频率为 2(如 col1 中的 1 和 col2 中的另一个 1)每个数字的频率可能不同。我需要重新调整两列,以便两列具有相等的频率划分。即每个数字应在左右列中出现 2/2=1,我只允许交换两列,ab。
  • 这不是打印问题,它是一个算法任务,如果你仍然没有得到我需要解释的内容,我可以详细说明吗?
  • 需要修改标题和编辑问题的信息,更清楚。每个值的计数是否始终为 2?

标签: c++ arrays algorithm stl-algorithm


【解决方案1】:

那个非常有趣的谜题!

首先我们需要做的是描述图论中的问题。图中的顶点是数组中的数字。在您的特定示例中,它将是 {1, 2, 3, 4, 5}。对于我们有边的每一行,所以在示例中我们得到这样的图:

这是无向图。出局的目标是指挥每一个边缘。如果我们有边 u, v,我们可以通过以下两种方式之一来引导它:

  • u -> v,表示我们选择的行是:u v
  • v -> u,表示我们选择的row为:v u

对于每个顶点 u 的出边数对应于左列中 u 的频率计数数。同理,输入边对应于右栏中的频率计数。

请注意,如果找到满足条件的边的方向:每个顶点具有相同数量的入边和出边,我们也将找到原始问题的解决方案。

所以现在让我描述如何找到这些方向。

我们将使用两个论文:

  1. 无向图具有欧拉回路当且仅当对于每个顶点 u,其边数都是偶数。
  2. 有向图具有欧拉回路当且仅当对于每个顶点 u,u 具有相同数量的入边和出边。

如果您从未听说过欧拉电路,以防万一:) https://en.wikipedia.org/wiki/Eulerian_path

从 1. 我们知道,图总是有解(因为,正如你在开头写的那样每个数字的频率是偶数)。从2.我们得到求解算法:首先我们要找到欧拉回路,然后根据它在回路中的出现来引导每条边。

还有如何找到欧拉回路的好教程:

Looking for algorithm finding euler path

【讨论】:

  • 我知道我可以使用 fleury 算法找到欧拉路径,但我正在寻找一种分析性强且无需进入图遍历即可处理频率的解决方案。感谢您的帮助!
  • 假设图形是无向的并遍历它并注意路径,然后修改以在相应边缘前面打印结果将花费大量时间。必须通过蛮力来更快地解决方案
  • @user6944972 所提出的算法只遍历每条边(原始输入中的线)一次,使其成为 O(n)。很难想象比这更快。当然你不会用蛮力变得更快。
  • 这是一个美丽的观察。只是一个非常小的旁注:可能值得一提的是,这必须为每个连接的组件单独完成。
  • @DanielWagner 谢谢! :)
【解决方案2】:

首先,简单总结一下问题:

我们有两列,其中包含许多不同的标记。 每个令牌出现偶数次。目标是交换行,以便最终每个标记在每列中出现相同的次数。

首先我浏览所有数据,计算每个标记出现的次数。

然后对于每个标记,我遍历每一列并检查是否出现了该特定标记。如果我在该列中遇到超过 n/2 个标记,则它会被交换。

重复整个过程,直到不再需要交换为止。

我不确定两件事:a) 一般而言,总会有解决问题的方法(我几乎可以肯定一定是这种情况......)? B)我能确定迭代总是会停止吗? IE。来回交换东西不会卡住吗?

无论如何,这里有一些代码可以做到这一点。请注意,没有检查输入是否正确等。

#include <iostream>
#include <string>
#include <vector>

using namespace std;

class my_pair
{
    private:
        int m_x,m_y;

    public:
        my_pair( int x, int y ) : m_x( x ), m_y( y ) {}

        void swap()
        {
            int tmp = m_x;
            m_x = m_y;
            m_y = tmp;
        }

        int x()
        {
            return m_x;
        }
        int y()
        {
            return m_y;
        }
};

int main()
{
    // Generate some input:
    // I'm assuming that the tokens in the columns are
    // in the form 0,1,2 etc such that the tokens
    // themselves can be interpreted as an index of an array.
    // I think there is no loss of generality here, as it can
    // be considered a re-labeling...

    vector<my_pair> pair_vector;

    pair_vector.push_back( my_pair( 0,1 ) );
    pair_vector.push_back( my_pair( 1,1 ) );
    pair_vector.push_back( my_pair( 2,2 ) );
    pair_vector.push_back( my_pair( 2,1 ) );
    pair_vector.push_back( my_pair( 2,0 ) );
    pair_vector.push_back( my_pair( 2,1 ) );
    pair_vector.push_back( my_pair( 2,1 ) );
    pair_vector.push_back( my_pair( 2,2 ) );

    cout << "Start vector:" << endl;

    for( auto p : pair_vector )
        cout << p.x() << ' ' << p.y() << endl;

    // 1: Count number of occurrences of each token.
    // Here the assumption on the tokens is used:
    vector<int> num_tokens;

    for( auto& p : pair_vector )
    {
        if( p.x()+1 > num_tokens.size() )
            num_tokens.resize( p.x()+1 );

        num_tokens[p.x()]++;

        if( p.y()+1 > num_tokens.size() )
            num_tokens.resize( p.y()+1 );

        num_tokens[p.y()]++;
    }


    // 2. Now I iterate through the columns for each token
    // and swap each token
    // that appears more often than n/2 times in that column,
    // where n is the number of appearances of each token:
    bool swap_was_performed = true;

    while( swap_was_performed )
    {
        int token = 0;
        swap_was_performed = false;

        for( auto& n : num_tokens ) // n is the number (or frequency) of tokens
        {
            int x_ctr = 0;
            int y_ctr = 0;

            // Iterating through the input columns:
            for( auto& p : pair_vector )
            {
                if( p.x()==token ) // x-values (i.e. the first column)
                {
                    x_ctr++;

                    if( x_ctr>n/2 )
                    {
                        p.swap();
                        swap_was_performed = true;
                    }
                }
            }

            for( auto& p : pair_vector )
            {
                if( p.y()==token ) // y-values...
                {
                    y_ctr++;

                    if( y_ctr>n/2 )
                    {
                        p.swap();
                        swap_was_performed = true;
                    }
                }
            }

            token++;
        }
    }


    cout << "After re-arranging:" << endl;

    for( auto p : pair_vector )
        cout << p.x() << ' ' << p.y() << endl;

}

【讨论】:

  • 不一定会有解决方案,但我已经找出了失败的案例。这个算法有点可疑。我也有这样的解决方案,但在很多情况下都失败了。
  • 是的,当每个元素都处于所需状态时,迭代将停止。
  • 在某些情况下,迭代不会停止,而是会进入来回交换行中条目的状态。原因是它从上到下遍历列,并在达到 N/2 个条目后开始交换所有内容。关键是要知道要交换哪些候选人。一个直接的改进是蒙特卡洛方法,即随机选择候选者进行交换和迭代,直到找到解决方案。我不确定即使这是否足以保证解决方案......
  • 我想出了一个灵魂,但它的复杂性是指数级的,这并不好。
猜你喜欢
  • 2020-06-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多