Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Алгиритм кодирования изображения, Хитрый алгоритм кодирования 
:(
    Опции темы
SwordOfDeath
  Дата 7.2.2012, 21:31 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 130
Регистрация: 16.10.2007

Репутация: нет
Всего: нет



Привет,

Вот возникла такая задачка:
Есть цветное изображение 100х100. Его нужно сжать, но для этого можно использовать только один метод. Мы можем задавать цвет не каждой точке индивидуально, а сразу непрерывной группе точек, задание цвета может быть вложенным, например в виде xml это может выглядеть вот так:
Код

<#FFFFFF>
    <pixel/>
    <pixel/>
    <pixel/>
    <pixel/>
    <pixel/>
    <#000000>
        <pixel/>
        <pixel/>
        <pixel/>
        <pixel/>
        <pixel/>
    </000000>
</FFFFFF>

В данном примере указано всего 10 пикселей, первые пять будут белые, а последние будут черного цвета. Тоесть цвет точки можно переопределять, а степень вложенности не ограничена.

Собственно задача выполнить сжатие этим методом максимально эффективно(минимальным количеством указания цвета). Тоесть если у нас к примеру 3 точки Черная, Белая, Черная. То у нас есть два варианта по очереди описать все три точки(это 3 указания цвета) либо задать глобально черный цвет а для белой точки переопределить его(это всего 2 указания цвета).
Первое что мне пришло на ум это построить бинарное дерево и на каждой ветке определять самый часто встречаемый цвет. Но это явно не самый эффективный алгоритм. Сдесь должно быть что-то адаптивное...

Если у вас есть какие-то идеи буду очень признателен! Спасибо!

PS: Еще раз напомню. Критерий эффективности: количество указаний цвета(чем меньше тем лучше).

Это сообщение отредактировал(а) SwordOfDeath - 7.2.2012, 23:28
PM MAIL   Вверх
Pavia
Дата 8.2.2012, 05:33 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 418
Регистрация: 6.12.2008

Репутация: 11
Всего: 12



Так смысла сжимать нет. 14 строчек против 10. По байтно сэкономили 10 байт потратили 24 дополнительных
PM MAIL   Вверх
SwordOfDeath
Дата 8.2.2012, 06:40 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 130
Регистрация: 16.10.2007

Репутация: нет
Всего: нет



Ну я же для примера такой формат привел... В реальной задаче на указание цвета тратится 30байт... Я этот формат не придумывал и не контролирую... Просто стоит задача: используя существующие возможности сжать данные по максимуму...

На данный момент: я определяю самый частоупотребляемый цвет, задаю его глобально, а потом для всех груп пикселей повторяющегося неглобального цвета переопределяю его.
Можно значительно еффективней.

PS. Если честно то я даже не понял вашу арифметику...
Если втупую определять цвет для каждой точки получим вот такое вот:
Код

<#FFFFFF><pixel/></FFFFFF>
<#FFFFFF><pixel/></FFFFFF>
<#FFFFFF><pixel/></FFFFFF>
<#FFFFFF><pixel/></FFFFFF>
<#FFFFFF><pixel/></FFFFFF>
<#000000><pixel/></000000>
<#000000><pixel/></000000>
<#000000><pixel/></000000>
<#000000><pixel/></000000>
<#000000><pixel/></000000>


Это сообщение отредактировал(а) SwordOfDeath - 8.2.2012, 06:48
PM MAIL   Вверх
tzirechnoy
Дата 8.2.2012, 12:46 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1173
Регистрация: 30.1.2009

Репутация: нет
Всего: 16



Отсортировать точки по цвету, очевидно, после чего указывать один цвет для каждой подряд идущей группы. Это будет абсолютно минимальный вариант: ведь каждый существующий в картинке цвет должэн быть указан, а здесь он будет указан ровно один раз.
PM MAIL   Вверх
Akina
Дата 8.2.2012, 14:37 (ссылка) |    (голосов:2) Загрузка ... Загрузка ... Быстрая цитата Цитата


Советчик
****


Профиль
Группа: Модератор
Сообщений: 20581
Регистрация: 8.4.2004
Где: Зеленоград

Репутация: 20
Всего: 454



tzirechnoy, он имеет в виду, что
Код

<#FFFFFF>
    <pixel/>
    <#000000>
        <pixel/>
    </000000>
    <pixel/>
</FFFFFF>

эффективнее, чем
Код

<#FFFFFF>
    <pixel/>
</FFFFFF>
<#000000>
    <pixel/>
</000000>
<#FFFFFF>
    <pixel/>
</FFFFFF>


SwordOfDeath, а существует ли возможность задания повторяющейся группы? типа

Код

<#FFFFFF count=2>
    <pixel/>
    <#000000 count=3>
        <pixel/>
    </000000>
    <pixel/>
</FFFFFF>


декодируемого в 10-пиксельную группу БЧЧЧББЧЧЧБ ?


--------------------
 О(б)суждение моих действий - в соответствующей теме, пожалуйста. Или в РМ. И высшая инстанция - Администрация форума.

PM MAIL WWW ICQ Jabber   Вверх
SwordOfDeath
Дата 8.2.2012, 18:32 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 130
Регистрация: 16.10.2007

Репутация: нет
Всего: нет



В том то и проблема... сами пиксели нужно указать полностью... 100х100 картинка будет иметь 10000 пикселей... Пиксели нельзя менять местами... они идут слева направо, сверху вниз... тоесть просто подряд...
Единственный метод сжатия который я могу применить это указание цвета групе пикселей с возможностью вложености(в таком случае цвет переопределяется). Структура очень похожа на XML...

Сейчас я определяю самый частоиспользуемый цвет(в картинке больше всего групп этого цвета) и задаю его глобально(оборачиваю все пиксели), а для всех остальных групп я переопределяю цвет локально(оборачиваю эту групу чем переопределяю цвет этих пикселей).
Это вполне нормальное решение но этого не достаточно... Расход на указание цвета очень высок, нужно выжать максимум.


Это сообщение отредактировал(а) SwordOfDeath - 8.2.2012, 18:36
PM MAIL   Вверх
Akina
Дата 8.2.2012, 19:50 (ссылка) |    (голосов:1) Загрузка ... Загрузка ... Быстрая цитата Цитата


Советчик
****


Профиль
Группа: Модератор
Сообщений: 20581
Регистрация: 8.4.2004
Где: Зеленоград

Репутация: 20
Всего: 454



SwordOfDeath, понял. 

Вроде бы Ваш алгоритм верен... но есть и случаи, когда он даст явно плохие результаты. Представьте кучу маленьких групп одного цвета, концентрирующихся в первой половине и редко встречающиеся во второй половине... и второго цвета, строго "наоборотного"... ведь разумнее поделить всю картинку на две части, и в каждой выбрать свой наиболее частовстречающийся цвет...

Когда появляется очередной открывающий тег? когда меняется цвет (будем считать, что мы имеем дело с потоком, а не с матрицей). Можем мы на них сэкономить? только за счёт восстановления предыдущего цвета.
Когда появляется очередной закрывающий тег? когда мы завершаем вложенный одноцветный блок. Можем мы на них сэкономить? нет, их будет ровно столько, сколько открывающих.

Можно попробовать (возможно, в значительной степени эмпирически) разработать некий критерий, который для данного цвета в данном фрагменте (само собой, начинающемся и заканчивающемся этим цветом) даст некий "коэффициент разумности" использования данного цвета в данном фрагменте в качестве базового. Его расчёт должен учитывать количество цветов, количество фрагментов, базовый цвет в момент начала фрагмента... одно радует - при расчёте такого коэффициента группу последовательных одноцветных пикселов можно сжать в один... Насколько это реально и насколько просто - не знаю пока... думать надо, а это займёт время, причём без гарантии результата.


--------------------
 О(б)суждение моих действий - в соответствующей теме, пожалуйста. Или в РМ. И высшая инстанция - Администрация форума.

PM MAIL WWW ICQ Jabber   Вверх
SwordOfDeath
Дата 9.2.2012, 02:09 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 130
Регистрация: 16.10.2007

Репутация: нет
Всего: нет



Akina
Мой алгоритм всегда дает результат лучше чем если бы я напрямую  оборачивал абсолютно все группы пикселей(каждую своим цветом).
То что вы предлагаете с разделением это все верно... можно создать рекурсивный алгоритм который будет делить все пространсво на 2 части и для каждого из них определял самый еффективный цвет. Это пожалуй максимум что я смог придумать пока. Но это просто бинарное дерево, а хочется чего-то адаптивного, как вы и предлагаете... только я пока так ничего и не придумал...

Благодарен за внимание...

PS Это действительно лучше рассматривать как поток. Формат проходит верификацию(скорее всего каким-то xml парсером) так что все елементы должны быть правильно открыты и закрыты, не допускается пересечение (<a><b></a></b>). Все возможные варианты хитростей я уже рассмотрел... = )
PPS Форум что-то падает постоянно... 
PM MAIL   Вверх
Mirkes
Дата 12.2.2012, 19:45 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 586
Регистрация: 18.8.2011
Где: Красноярск

Репутация: 4
Всего: 17



ПРЕДЛАГАЕТСЯ СРАВНЕНИЕ НЕСКОЛЬКИХ МЕТОДОВ
Рассматривать будем картинки, после операции фильтрации, заменившей все подряд идущие пиксели одного цвета на один пиксел.
Введем некоторые обозначения
N – число смен цветов в картинке. Самая тупая оценка – N установок цвета.
Метод обрамления самым распространенным цветом среди групп. Оценка качества N-k+1, где k – число групп самого распространенного цвета.
Для определения максимально возможного сжатия используем метод глобального поиска минимума. Он NP полный (оценка порядка 2^N).
Как следствие предлагается использовать длину картинки порядка 100 (моя машина на больших размерностях не потянет).
Чисто поточный метод. Идея состоит в том, что при поступлении очередного пикселя определяется, есть ли он в стеке установленный на данный момент цветов, и, если есть, производится сброс до этого цвета, иначе – установка его в стек. Метод очень скоростной, но не самый лучший (качество его работы видно в статистике в приложенном файле). Оценка трудозатрат – N.
Оконно-поточный метод. Комбинация двух методов. Задаем ширину окна, равную n. Поток режется на куски по n элементов. Производится оптимизация кодирования в окне. Для каждого окна параметрами являются – набор пикселей и ранее сформированный стек. Оценка трудозатрат на этот метод равна (N/n)*2^n. Очевидно, что при n=N он дает глобальный поиск, а при n=1 – чисто поточный.
Сравнение строилось на картинках длиной в 50 пикселей, полученных случайной генерацией. Число цветов в картинках варьировалось от 5 до 20 с шагом 5.
Размер n варьировался от 5 до N/2 c шагом в 5
Из статистики видно, что при n=N/2 результат почти всегда тот же, а трудозатраты на несколько порядков меньше. Трудозатраты измерены в попугаях – числе вызовов процедуры выбора варианта продолжения.
Далее дело Вашего выбора что важнее – степень сжатия или время.

Приложенный код довольно странный, но писался для себя
Код

import java.awt.Dimension;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.HeadlessException;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import java.util.Random;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JScrollPane;
import javax.swing.JSpinner;
import javax.swing.JTextPane;
import javax.swing.SpinnerNumberModel;
import javax.swing.SwingUtilities;


public class PictureCode extends JFrame implements ActionListener {
    private JTextPane pic = new JTextPane();
    private JTextPane res = new JTextPane();
    private JSpinner colors = new JSpinner(new SpinnerNumberModel(50, 1, 200, 10));
    private Random rnd = new Random();
    private static final int picSize = 50;
    private int[] wholePic = new int[picSize];
    private int[] filterPic = new int[picSize + 1];
    private int[] code = new int[picSize + 1];
    private int[] stack = new int[picSize + 1];
    private int[] bestCode = new int[picSize + 1];
    private int min, minn, full, last,calls;
    private int[] testPic =
    { 0, 2, 0, 4, 0, 4, 2, 0, 1, 2, 0, 1, 3, 0, 3, 4, 2, 0, 2, 3, 1, 4, 0, 2, 4, 2, 1, 3, 1, 4, 0, 1, 2, 0, 4, 3, 4, 1,
      4, 1, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3 };


    public PictureCode() throws HeadlessException {
        super("Picture coder");
        setLayout(new GridBagLayout());
        Insets ins = new Insets(3, 3, 3, 3);
        //        JLabel lab = new JLabel("Number of colors");
        getContentPane().add(new JLabel("Number of colors"),
                             new GridBagConstraints(0, 0, 1, 1, 0, 0, GridBagConstraints.CENTER,
                                                    GridBagConstraints.NONE, ins, 0, 0));
        getContentPane().add(colors,
                             new GridBagConstraints(1, 0, 1, 1, 0, 0, GridBagConstraints.CENTER, GridBagConstraints.NONE,
                                                    ins, 0, 0));
        JButton but = new JButton("Generate picture");
        but.setActionCommand("gener");
        but.addActionListener(this);
        getContentPane().add(but,
                             new GridBagConstraints(0, 1, 2, 1, 0, 0, GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL,
                                                    ins, 0, 0));
        but = new JButton("Total search");
        but.setActionCommand("total");
        but.addActionListener(this);
        getContentPane().add(but,
                             new GridBagConstraints(0, 2, 2, 1, 0, 0, GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL,
                                                    ins, 0, 0));
        but = new JButton("Statistica");
        but.setActionCommand("statist");
        but.addActionListener(this);
        getContentPane().add(but,
                             new GridBagConstraints(0, 3, 2, 1, 0, 0, GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL,
                                                    ins, 0, 0));
        but = new JButton("Special");
        but.setActionCommand("spec");
        but.addActionListener(this);
        getContentPane().add(but,
                             new GridBagConstraints(0, 4, 2, 1, 0, 0, GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL,
                                                    ins, 0, 0));


        getContentPane().add(new JLabel("Picture colors"),
                             new GridBagConstraints(2, 0, 1, 1, 0, 0, GridBagConstraints.CENTER,
                                                    GridBagConstraints.NONE, ins, 0, 0));
        getContentPane().add(new JLabel("Result code"),
                             new GridBagConstraints(3, 0, 1, 1, 0, 0, GridBagConstraints.CENTER,
                                                    GridBagConstraints.NONE, ins, 0, 0));

        getContentPane().add(new JScrollPane(pic),
                             new GridBagConstraints(2, 1, 1, 5, 1, 1, GridBagConstraints.CENTER, GridBagConstraints.BOTH,
                                                    ins, 0, 0));
        getContentPane().add(new JScrollPane(res),
                             new GridBagConstraints(3, 1, 1, 5, 1, 1, GridBagConstraints.CENTER, GridBagConstraints.BOTH,
                                                    ins, 0, 0));


        setMinimumSize(new Dimension(800, 300));
        setLocationRelativeTo(null);
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                new PictureCode().setVisible(true);
            }
        });
    }

    public void filter() {
        int j = 0, k = -1;
        for (int i = 0; i < picSize; i++)
            if (wholePic[i] != k) {
                k = wholePic[i];
                filterPic[j++] = k;
            }
        filterPic[picSize] = j;
    }

    private void restoreStack(int ind) {
        stack[picSize] = 0;
        full=0;
        for (int i = 0; i < ind; i++) {
            if (code[i] < 0){
                stack[picSize] += code[i];
            }else{
                stack[stack[picSize]++] = code[i];
                full++;
            }
        }
    }

    private void find(int ind) {
        // Cutter
        //        int n=0;
        //        for (int i=0;i<ind;i++)
        //            if (code[i]>=0)
        //                n++;
        //        System.out.println("n "+n+" full "+full+" ind "+ind);
        //        if (full!=n)
        //            System.exit(1);
        calls++;
        if (full >= min)
            return;
        // the end??
        if (ind == last) {
            // calc result
            if (full < min) {
                if (min == picSize)
                    minn = full;
                min = full;
                System.arraycopy(code, 0, bestCode, 0, picSize);
            }
            return;
        }
        // there exist in stack?
        for (int i = stack[picSize] - 1; i >= 0; i--)
            if (stack[i] == filterPic[ind]) {
                code[ind] = i - stack[picSize] + 1;
                stack[picSize] = i + 1;
                find(ind + 1);
                restoreStack(ind);
                break;
            }
        // add to stack
        stack[stack[picSize]++] = filterPic[ind];
        code[ind] = filterPic[ind];
        full++;
        find(ind + 1);
        full--;
    }

    public void totalFind() {
        stack[0] = filterPic[0];
        code[0] = filterPic[0];
        stack[picSize] = 1;
        min = picSize;
        last = filterPic[picSize];
        full = 1;
        calls=0;
        find(1);
    }

    public void windowFind(int width) {
        stack[picSize] = 0;
        bestCode[0] = filterPic[0];
        full = 0;
        last = 0;
        int start = 0;
        calls=0;
        do {
            last += width;
            if (last > filterPic[picSize])
                last = filterPic[picSize];
            min = picSize;
            System.arraycopy(bestCode, 0, code, 0, picSize);
            restoreStack(start);
            find(start);
            start += width;
        } while (last < filterPic[picSize]);
    }

    public void drawBestCode() {
        for (int i = 0; i < filterPic[picSize]; i++) {
            System.out.print("" + bestCode[i] + '\t');
        }
        System.out.println();
    }

    public void drawFilter() {
        for (int i = 0; i < filterPic[picSize]; i++) {
            System.out.print("" + filterPic[i] + '\t');
        }
        System.out.println();
    }

    public void restoreControl() {
        int st = 0;
        int err = 0;
        int n = 0;
        for (int i = 0; i < filterPic[picSize]; i++) {
            if (bestCode[i] < 0) {
                st += bestCode[i];
            } else {
                stack[st++] = bestCode[i];
                n++;
            }
            if (filterPic[i] != stack[st - 1])
                err++;
        }
        if (err > 0)
            System.out.println("min\t" + n + "\terrors\t" + err);
    }

    @Override
    public void actionPerformed(ActionEvent e) {
        if ("gener".equals(e.getActionCommand())) {
            String s = "";
            int cols = ((SpinnerNumberModel)colors.getModel()).getNumber().intValue();
            for (int i = 0; i < picSize; i++) {
                wholePic[i] = rnd.nextInt(cols);
                s += " " + wholePic[i];
            }
            pic.setText(s);
        } else if ("total".equals(e.getActionCommand())) {
            String s;
            filter();
            s = "After filtration " + filterPic[picSize] + '\n';
            res.setText(s);
            stack[0] = filterPic[0];
            code[0] = filterPic[0];
            stack[picSize] = 1;
            min = picSize;
            full = 1;
            find(1);
            s += "Total minimum " + min + " stream minimum " + minn + '\n';
            for (int i = 0; i < filterPic[picSize]; i++)
                s += " " + code[i];
            res.setText(s);
        } else if ("statist".equals(e.getActionCommand())) {
            for (int cols = 5; cols < 25; cols += 5) { // number of color
                for (int f = 0; f < 10; f++) { // number of test
                    // generation
                    for (int i = 0; i < picSize; i++) {
                        wholePic[i] = rnd.nextInt(cols);
                    }
                    // filtering
                    filter();
                    System.out.println("colors \t" + cols + "\ttest#\t" + f + "\tgroups num\t" + filterPic[picSize]);
//                    drawFilter();
                    totalFind();
                    System.out.println("total\t" + min + "\tstream\t" + minn+"\tcalls\t"+calls);
                    restoreControl();
//                    drawBestCode();
                    for (int width = 5; width <= picSize / 2; width += 5) {
                        windowFind(width);
                        System.out.println("width\t" + width + '\t' + min+"\tcalls\t"+calls);
                        restoreControl();
//                        drawBestCode();
                    }
                }
            }
        } else if ("spec".equals(e.getActionCommand())) {
            // copy testPic to wholePic
            System.arraycopy(testPic, 0, wholePic, 0, picSize);
            filter();
            System.out.println("colors \t" + "5" + "\ttest#\t" + "2" + "\tgroups num\t" + filterPic[picSize]);
//            drawFilter();
            totalFind();
            System.out.println("total\t" + min + "\tstream\t" + minn);
//            drawBestCode();
            for (int width = 5; width <= picSize / 2; width += 5) {
                windowFind(width);
                System.out.println("width\t" + width + '\t' + min);
//                drawBestCode();
            }

        }
    }
}



Присоединённый файл ( Кол-во скачиваний: 1 )
Присоединённый файл  stat.rar 3,17 Kb


--------------------
Mirkes
PM MAIL   Вверх
SwordOfDeath
Дата 14.2.2012, 23:09 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 130
Регистрация: 16.10.2007

Репутация: нет
Всего: нет



Mirkes,
Простите за поздний ответ, компьютер накрылся...

Я в джаве не очень, да и с алгоритмами тоже слабо дружу... А вы я смотрю изучали алгоритмы, видимо поэтому мне сложно понять вашу мысль )

Я так понял вы предлагаете просто в лоб(перебором) подбирать самый еффективный вариант растановки цветов, а для снижения сложности предлагаете выполнять перебор только по определенному окну?
Насколько я понял ваш метод вы протестировали на потоке из 100 пикселей? Тогда у нас беда... так как задача сделать это на ~10тыс. пикселей(100х100).
Хотя соглашусь что ваш метод на данный момент решает задачу полностью... Но сложность слишком высока.

PS Огромное спасибо за код... немного посмотрю как это на джаве выглядит. Свой алгоритм пишу на С++.

Это сообщение отредактировал(а) SwordOfDeath - 14.2.2012, 23:11
PM MAIL   Вверх
Mirkes
Дата 17.2.2012, 10:02 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 586
Регистрация: 18.8.2011
Где: Красноярск

Репутация: 4
Всего: 17



Цитата(SwordOfDeath @  14.2.2012,  23:09 Найти цитируемый пост)
Я так понял вы предлагаете просто в лоб(перебором) подбирать самый еффективный вариант растановки цветов, а для снижения сложности предлагаете выполнять перебор только по определенному окну?

К сожалению я не дружу с С :(
В своем посте я рассмотрел три алгоритма.
Ниже я привел описание трех предложенных алгоритмов на псевдокоде, полученном из дикой смести C,Java,Pascal и 1С smile)

Для подсчета трудоемкости использкем следующие обозначения:
m - число групп пикселов одного цвета, идущих подряд. (если пикселы 1123331 то будет четыре группы 1231)
n - ширина окна для кодирования.
Stack - стек включенных на данный момент цветов
d - текущая глубина стека.
Est - текущее количество включений цвета.
Min - Текущий минимум включений цвета для полного кода
Code - массив для записи процедуры кодирования
BestCode - массив с записью лучшего кода
Pic - массив номеров цветов групп

Задача в исходной постановке является плохой - то есть NP полной.
Метод 1
Перебираем все возможные варианты.
s=0
Est=0
Min=10000000
Find(0)
Процедура Find(int j)
Если Est=Min Тогда
   Возврат - уже сделано столько же открытий, как в учшем варианте, а еще не все. Точно будет хуже, можно не смотреть.
Конец Если
Если j=m тогда
  Это полный код.
  Если Min>Est тогда
     Новый минимум найден.
     Min=Est
     BestCode=Code
  Конец если 
  Возврат
КонецЕсли
//Пытаемся получить цвет закрытием одного или нескольких цветов
Ищем наибольший номер k элемента стека с цветом Pic[j]
Если нашли тогда 
  Code[j]=d-k+1 (Плюс 1 в моей реализации. По сути нужно указать число ранее открытых цветов, которые следует закрыть)
  d=k
  Find[j+1]
  Восстанавливаем стек по массиву Code. Может есть смысл перед обработкой создавать копию стека - не знаю. Таких копий может потребоваться много.
Конец если
//Получаем цвет открытием цвета
Est=Est+1    еще одно открытие группы
Code[j]=Pic[j]
Find(j+1)
Est=Est-1    готовимся к откату
Конец процедуры

Достоинство метода - гарантированно найдет минимум
Недостаток - в худшем варианте 2^m вариантов при m=10000 это что-то около 10^300 вариантов, то есть бесконечно много

Метод 2
Строим максимально быстро
Идея метода примитивна и проста.
For i=0 To m-1 Do 
  Если в стеке есть цвет Pic[i] тогда
    Code[i]=d-k+1 (Плюс 1 в моей реализации. По сути нужно указать число ранее открытых цветов, которые следует закрыть)
    d=k
  Иначе
    Est=Est+1    еще одно открытие группы
    Code[i]=Pic[i]
  Конец если
Конец цикла

Достоинство метода - просмотр всего одной цепочки
Недостаток - чаще всего решение далеко от оптимального

Метод 3
Оконный метод
Потребуется еще пара переменных - 
Last - текущий конец просматриваемого участка
Start - текущее начало просматриваемого участка


s=0
Est=0
Last = -1;
Цикл (он будет с постусловием!)
   Start=Last+1
   Last=Last+n   // конец окна, для которого будем работать
   Если Last>m тогда
      Last=m
   Конец если
   Min=10000000
   Find(Start)
   Code=BestCode (восстанавливаем лучший код начального участка для продолжения)
   Est=Min
   Восстанавливаем стек по массиву Code. Может есть смысл перед обработкой создавать копию стека - не знаю. Таких копий может потребоваться много.
Конец цикла если Last=m

Процедура Find(int j)
Если Est=Min Тогда
   Возврат - уже сделано столько же открытий, как в учшем варианте, а еще не все. Точно будет хуже, можно не смотреть.
Конец Если
Если j=Last тогда
  Это полный код.
  Если Min>Est тогда
     Новый минимум найден.
     Min=Est
     BestCode=Code
  Конец если 
  Возврат
КонецЕсли
//Пытаемся получить цвет закрытием одного или нескольких цветов
Ищем наибольший номер k элемента стека с цветом Pic[j]
Если нашли тогда 
  Code[j]=d-k+1 (Плюс 1 в моей реализации. По сути нужно указать число ранее открытых цветов, которые следует закрыть)
  d=k
  Find[j+1]
  Восстанавливаем стек по массиву Code. Может есть смысл перед обработкой создавать копию стека - не знаю. Таких копий может потребоваться много.
Конец если
//Получаем цвет открытием цвета
Est=Est+1    еще одно открытие группы
Code[j]=Pic[j]
Find(j+1)
Est=Est-1    готовимся к откату
Конец процедуры

Достоинство метода - по времени он промежуточный. В худшем случае число просматриваемых вариантов порядка (m/n)*n^2
Недостаток метода - он часто дает не оптимальные решения, но они много лучше чем у второго метода.

Сравнение методов
Метод      Трудозатраты     точность
1                  2^m                 Оптимальная
2                  1                      Паришивая
3                  (m/n)*2^n        Приемлемая

Пояснения
В проведенных мной экспериментах при малой длине окна результаты в половине случаев совпадали с глобальным минимумом
Но я экспериментировал при малых длинах.
Думаю Вам следует провести серию экспериментов на полных рисунках и выяснить при какой длине окна Вы получите приемлемую точность за разумное время.

Альтернативой предложенным методам может быть только набор эвристик. Типа комбинацию 121 кодировать как уст 1 уст 2 сборс 1.
Я не смог придумать чего-то более разумного, но вдруг Вы сможете. Удачи


--------------------
Mirkes
PM MAIL   Вверх
SwordOfDeath
  Дата 18.2.2012, 02:19 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 130
Регистрация: 16.10.2007

Репутация: нет
Всего: нет



Mirkes
Огромное спасибо, а я ведь даже и не мечтал о такой существенной помощи. Воистину благодарен! (плюсик поставил!)

Сейчас в голове крутится очень много всего, нужно как-то все это систематизировать. Как напишу алгоритм обязательно выложу сюда... smile 

PM MAIL   Вверх
  
Ответ в темуСоздание новой темы Создание опроса
Правила форума "Алгоритмы"

maxim1000

Форум "Алгоритмы" предназначен для обсуждения вопросов, связанных только с алгоритмами и структурами данных, без привязки к конкретному языку программирования и/или программному продукту.


Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, maxim1000.

 
1 Пользователей читают эту тему (1 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | Алгоритмы | Следующая тема »


 




[ Время генерации скрипта: 0.0946 ]   [ Использовано запросов: 20 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.