【问题标题】:Optimizing this C# algorithm优化此 C# 算法
【发布时间】:2013-02-19 22:55:35
【问题描述】:

这是一个算法问题,我有解决方案,但它有性能问题。

问题描述

有 n 个变量和 m 个要求。需求表示为 (x

输入格式:

输入的第一行包含两个整数 n 和 m。 然后是 m 行,每行包含 2 个空格分隔的整数 x 和 y,这意味着一个要求 (x

输出格式:

在一行中输出答案。

约束:

0

0

0

示例输入:

6 7

1 3

0 1

2 4

0 4

2 5

3 4

0 2

样本输出

1000

以下是我的解决方案。当 n=13 和 m=199 时,需要很长时间才能得到结果,但可接受的时间是 5 秒。

那么任何人都可以想出更好的方法来进一步优化它吗?谢谢。

我目前的解决方案:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ConsoleApplication81
{
    class Program
    {
        const int N = 10;
        static List<Condition> condition = new List<Condition>();
        static void Main(string[] args)
        {
            string[] line1 = Console.ReadLine().Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
            int n = int.Parse(line1[0]);
            int m = int.Parse(line1[1]);

            for (int i = 0; i < m; i++)
            {
                string[] line = Console.ReadLine().Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
                condition.Add(new Condition()
                {
                    X = int.Parse(line[0]),
                    Y = int.Parse(line[1])
                });
            }

            //
            List<int[]> rlist = new List<int[]>();

            for (int j = 0; j < N; j++)
            {
                int[] assignments = new int[n];
                for (int i = 0; i < n; i++)
                    assignments[i] = -1;
                assignments[0] = j;
                rlist.Add(assignments);
            }
            for (int j = 1; j < n; j++)
            {
                List<int[]> rlist2 = new List<int[]>(rlist.Count*5);
                for (int k = 0; k < rlist.Count; k++)
                {
                    for (int l = 0; l < N; l++)
                    {
                        rlist[k][j] = l;
                        if (CanPassCondition(rlist[k]))
                            rlist2.Add((int[])rlist[k].Clone());
                    }
                }
                rlist = rlist2;
            }

            Console.Write(rlist.Count % 1007);
        }


        private static bool CanPassCondition(int[] p)
        {
            foreach (var c in condition)
            {
                if (p[c.X] == -1 || p[c.Y] == -1)
                    continue;

                if (p[c.X] > p[c.Y])
                    return false;
            }
            return true;
        }
    }

    class Condition
    {
        public int X;
        public int Y;

        public override string ToString()
        {
            return string.Format("x:{0}, y:{1}", X, Y);
        }
    }
}

【问题讨论】:

  • 可能会记录一些日志以查看是否有任何不必要的执行。添加计时块以查看需要很长时间才能执行的操作。
  • 任何情况下,即使 for 循环只有一个衬里,也要放置那些该死的大括号。
  • @JanDvorak 不一定。我在支持大括号的阵营。但是有些人觉得单行省略大括号时,代码看起来更简洁,更简洁。如果它完全没用,语言的设计者不会给出这个选项。表达自己的观点和信念是可以的,但在向学生提供关于不明确的问题的建议时必须谨慎行事。至少必须说明这两种方法的优点。此外,最好避免粗鲁(回复:“该死的大括号”)。
  • @JanDvorak 我的意思是缺少 c# 的力量,尤其是在循环中。像这样的东西可以用来创建一个列表,而不是使用 for 循环进行迭代。 List x = Enumerable.Repeat(value, count).ToList();
  • @IsaacCambron 这是来自hackerrank.com 的问题。页面在这里hackerrank.com/challenges/requirement

标签: c# algorithm


【解决方案1】:

这里有一个 Java 解决方案,即使在 n=13, m=199 的情况下,它对我来说也能快速运行:

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.HashMap;
import java.util.Map;

public class Assignments
{
    private static Map <String, Long> solutions = new HashMap <String, Long> ();

    private static boolean [][] constraints;

    private static long solve (int n, int [] low, int [] high)
    {
        StringBuilder sb = new StringBuilder ();

        for (int i = 0; i < n; i++)
        {
            sb.append (low [i]);
            sb.append (high [i]);
        }

        String signature = sb.toString ();

        Long result = solutions.get (signature);
        if (result == null)
        {
            result = Long.valueOf (doSolve (n, low, high));
            solutions.put (signature, result);
        }

        return result.longValue ();
    }

    private static long doSolve (int n, int [] low, int [] high)
    {
        if (n == 0) return 1;
        else
        {
            long result = 0;

            for (int i = low [n - 1]; i <= high [n - 1]; i++)
            {
                int [] l = new int [n - 1];
                int [] h = new int [n - 1];

                for (int j = 0; j < n - 1; j++)
                {
                    l [j] = constraints [n - 1][j] ? Math.max (low [j], i) : low [j];
                    h [j] = constraints [j][n - 1] ? Math.min (high [j], i) : high [j];
                }

                result += solve (n - 1, l, h);
            }

            return result;
        }
    }

    public static void main(String[] args) throws Exception
    {
        BufferedReader reader = 
            new BufferedReader (
                new InputStreamReader(System.in));

        String nm = reader.readLine ();
        String [] pair = nm.split(" ");
        int n = Integer.parseInt(pair [0]);
        int m = Integer.parseInt(pair [1]);

        constraints = new boolean [n][];
        for (int i = 0; i < n; i++)
            constraints [i] = new boolean [n];

        int [] low = new int [n];
        int [] high = new int [n];
        for (int i = 0; i < n; i++)
            high [i] = 9;

        for (int i = 0; i < m; i++)
        {
            String ab = reader.readLine();
            pair = ab.split (" ");
            int a = Integer.parseInt(pair [0]);
            int b = Integer.parseInt(pair [1]);
            constraints [a][b] = true;
        }

        System.out.println(solve (n, low, high));
    }
}

实际上,一旦你有 13 个变量,你可能只有 156 (13 * 12) 个有意义的约束,但是。

示例输入:

13 1
3 8

输出:

5500000000000

另一个示例输入:

13 12
0 1
1 2
2 3
3 4
4 5
5 6
6 7
7 8
8 9
9 10
10 11
11 12

输出:

497420

【讨论】:

  • 最难的测试是:13 1 而不是 13 199。所有排列的计数对于此任务来说是不正确的解决方案,因为结果可能具有值 n!
  • 对于 n = 13, m = 1,我的算法几乎立即返回 5500000000000
  • @MikhailVladimirov 谢谢你的回答。我从中学到了两个好处。 1) 将约束存储在 bool 数组中; 2)存储部分答案并重用它们以避免第二次计算它们。 PS。最后一行代码是硬编码的13,应该是n,正确答案应该是1007。
  • @rockXrock 不错。固定。
  • @MikhailVladimirov 如果你也添加一些关于你的算法的解释会很棒
猜你喜欢
  • 1970-01-01
  • 2021-06-29
  • 2012-09-05
  • 2023-03-09
  • 1970-01-01
  • 2019-02-24
  • 1970-01-01
  • 2011-05-24
  • 1970-01-01
相关资源
最近更新 更多