假设我们有n个不相交的水平双杠。然后,我们需要用垂直线连接每对条形图,因此总共有sum(n,...,1)条线。如果两个条之间的这些连接中的任何一条与其他条相交p倍,那么我们说成本为p。问题是找到n条的最低总成本。

n=1, p=0:     n=2, p=0:     n=3, p=0  n=4, p=0:

                              ---        -----
                              | |        | | |
---          ---            --- |      --- | |
               |              | |      | | | |
               ---            ---      | --- |
                                       |   | |
                                       -------

n=6, p=3:
-------------
| |     | | |
| ----- | | |
| | | | | | |
| | | --- | |
| | | | | | |
--*-*-- | | |
  | |   | | |
  | ----*-- |
  | |   |   |
  -----------

n=7, p=6:
---------------
| | |     | | |
| --*---- | | |
| | | | | | | |
| | | --*-- | |
| | | | | | | |
| | --- | | | |
| | | | | | | |
| | | --*-*-- |
| | | | | |   |
--*-*---- |   |
  | |     |   |
  -------------

n=8, p=11
-------------------
| | | |       | | |
| --1-1------ | | |
| | | |     | | | |
| | --2---- | | | |
| | | | | | | | | |
| | | | | --1-- | |
| | | | | | | | | |
| | | --1-- | | | |
| | | | |   | | | |
| | | | ----1-1-- |
| | | | |   | |   |
--1-1-1------ |   |
  | | |       |   |
  -----------------

关于如何找到其背后的模式或逻辑的任何暗示都将是很棒的。

最佳答案

这是一个使用蛮力解决问题的草稿解决方案,假设可以在仅具有n + 1列的网格中找到n条钢筋的最佳解决方案(这种假设至少在n> = 8时似乎是错误的。搜索可以扩展,最差的情况是sum(n-1,... 1),但这将进一步减慢搜索速度,主要是通过添加冗余解决方案。

该算法具有指数复杂性,并且仅在非常小的时间内在有用的时间内给出结果。正如我在评论中说的,可以通过减少搜索空间来改进此方法,方法是减少搜索空间,仅允许使用具有沙钟形形状的条形组合(外面的长条,里面的短条,最外面的条最长,覆盖相同的空间,以及所有其他形状)条形图可以放置在最外面的列中)。但是到目前为止,我发现没有其他有用的属性可以使用。请注意,可能存在某些属性仅对某些最佳解决方案才适用,例如中心栏长度为2。

更好的方法可能是使用精确的sum(n-1,... 1)列,每个连接都有自己的列,变体的数量实际上可能更少。

我不知道是否存在有用的动态编程解决方案。

public class BarConnection {

    static class Bar {
        int start, end;
        private final int maxlength, minlength;

        Bar(int maxlength, int minlength) {
            this.maxlength = maxlength;
            this.minlength = minlength;
            reset();
        }

        public boolean next() {
            start++;
            if (start > 0) {
                return reset((end - start) + 2);
            }
            end++;
            return true;
        }

        public void reset() {
            reset(minlength);
        }

        public boolean reset(int length) {
            if (length > maxlength) {
                return false;
            }
            start = -length;
            end = 0;
            return true;
        }
    }

    static class Solution {
        private Bar[] bars;
        private int globalmin, globalmax, cost;

        Solution(int n) {
            bars = new Bar[n];
            for (int i = 0; i < n; i++) {
                bars[i] = new Bar(/* maxlength */ n, /* minlength */ 1);
            }
        }

        private boolean connect(final int maxcost) {
            cost = Integer.MAX_VALUE;
            int sumcost = 0;
            for (int i = 0; i < (bars.length - 1); i++) {
                for (int j = i + 1; j < bars.length; j++) {
                    final int pairCost = minCostBetween(i, j);
                    if (pairCost == 0) {
                        continue;
                    }
                    sumcost += pairCost;
                    if (sumcost > maxcost) {
                        return false;
                    }

                }
            }
            cost = sumcost;
            return true;
        }

        boolean nextSolution(final int maxcost) {
            while (true) {
                while (bars[0].next()) {
                    if (connect(maxcost)) {
                        return true;
                    }
                }
                bars[0].reset();
                for (int i = 1; i < bars.length; i++) {
                    if (bars[i].next()) {
                        break;
                    }
                    if (i == bars.length - 1) {
                        return false;
                    }
                    bars[i].reset();
                }
                if (connect(maxcost)) {
                    return true;
                }
            }
        }

        private int minCostBetween(final int i, final int j) {
            int minConnectionCost = -1;
            for (int k = Math.max(bars[i].start, bars[j].start); k <=
                    Math.min(bars[i].end, bars[j].end); k++) {
                // calculate cost for connecting at column k
                int newcost = 0;
                for (int l = i + 1; l < j; l++) {
                    final Bar midbar = bars[l];
                    if ((k >= midbar.start) && (k <= midbar.end)) {
                        newcost++;
                        if ((minConnectionCost >= 0) && (newcost >=
                                minConnectionCost)) {
                            break;
                        }
                    }
                }
                if ((minConnectionCost < 0) || (newcost < minConnectionCost)) {
                    minConnectionCost = newcost;
                    if (newcost == 0) {
                        break;
                    }
                }
            }
            return minConnectionCost;
        }
    }


    public static void main(String[] args) {
        int n = 6
        final Solution searchState = new Solution(n);
        int minCost = Integer.MAX_VALUE;
        while(true) {
            if (!searchState.nextSolution(minCost - 1)) {
                break;
            }
            minCost = searchState.cost, minCost;
            if (minCost == 0) {
                break;
            }
        }

        System.out.println("n=" + n + ", p=" + minCost);
    }
}

关于java - N条平行线上的最小交叉点,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/58316038/

10-13 05:00