POJ 1009 解题报告

先说一下解题过程:

  爆破肯定不行,题目结尾也给出了。那只能考虑别的思路。由题目中的输入输出格式(都是线段)我们可以想到:输入中的线段端点与输出中的线段端点有关系,可以以此为突破口。

  我首先假设的是,推论一:output线段起点一定在input线段端点(起点和终点)的九宫格覆盖内(这里的覆盖可以回绕,即跨行,见下图,图中绿色方格能够覆盖所有红色标记的方格)

  后来经过验证,发现一个更严格的条件,推论2,除了左下角以外的所有output线段起点,都在input线段起点的九宫格覆盖内。以下对一般情况进行证明(其他边界或者特殊情况类似,不再赘述):

  1. 考虑除了左下角以外的所有output线段起点:

    反证法:考虑除了左下角以外的所有output线段起点, 假设存在一个起点不在input线段起点的九宫格覆盖内,那么在input中肯定是下面的情况:

    绿色点为output线段起点,由于该图中没有起点,所以图中同一行元素只能是相同的。由于第一列的元素肯定都不是起点,即前面肯定还有相同的点,即下图:

    此时黄色点和绿色点,在output中的值一样,所以绿色点肯定不是output中的线段起点,与假设矛盾。

    注意:如果没有那么多列,可以进行回绕来得到上图,对于上下边界情况,是残缺的九宫格,但结论是一样的,感兴趣的可以证明一下。

  2. 左下角为output起点的情况,看下图:

  

  在上图中我标出了绿色点的九宫格(回环后的),可以看出绿色点并不在某个input起点的覆盖内,但它确实是一个起点(与上图中的黄色字体所在格的output值不同)。

上面的推论一和推论二都是正确的,注意假设二中的左下角在右下角的的回环覆盖内的,所以也是正确的,下面是代码,使用推论二:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#define PI 3.14159265359

int resset[9001][2], setcnt;    // 0 表示1维索引, 1 颜色
int pair[1001][3];              // 0 value, 1 count, 2 accumulated count
int w, h, pairs, pixels;
int end[1001], numend;          // 输入端点的1维索引

int cmp_func(const void *a, const void *b)
{
    int x = *(int *)a, y = *(int *)b;
    if(x < y) return -1;
    else if(x == y) return 0;
    else return 1;
}
// bi-section search
int getValue(int idx)
{
    int start = 0, end = pairs-1;
    while(start < end)
    {
        int mid = (start + end) >> 1;
        if(pair[mid][2] <= idx) start = mid+1;
        else end = mid;
    }

    return pair[start][0];
}
// int getValue(int idx)
// {
//     for(int i = 0; i < pairs; i++)
//     {
//      if(idx < pair[i][2]) return pair[i][0];
//     }
// }

int main()
{
    int indeces[9][3] = {{-1, -1}, {-1, 0}, {-1, 1}, {0, -1 }, {0, 0}, {0, 1}, {1, -1 }, {1, 0}, {1, 1}};
    while(1)
    {
        scanf("%d", &w);
        if(0 == w) break;
        indeces[0][2] = -w-1;indeces[1][2] = -w;indeces[2][2] = -w+1;
        indeces[3][2] = -1;  indeces[4][2] = 0; indeces[5][2] = 1;
        indeces[6][2] = w-1; indeces[7][2] = w; indeces[8][2] = w+1;

        memset(pair, 0, sizeof(pair));
        memset(end, 0, sizeof(end));
        memset(resset, 0, sizeof(resset));
        numend = setcnt = pixels = 0;
        for(int i = 0; ; i++)
        {
            scanf("%d%d", &pair[i][0], &pair[i][1]);
            if(0 == pair[i][0] && 0 == pair[i][1])
            {
                pairs = i;
                break;
            }
            pixels += pair[i][1];
            if(0 == i)
            {
                end[numend] = 0;
                pair[i][2] = pair[i][1];
            }
            else
            {
                end[numend] = end[numend-1] + pair[i-1][1];
                pair[i][2] = pair[i-1][2] + pair[i][1];
            }
            numend++;
            // if(pair[i][1] > 1)       // 最初AC用的推论// {
            //  end[numend] = end[numend-1] + pair[i][1] - 1;
            //  numend++;
            // }
        }
        h = pixels / w;
        // 找出输出图像中所有的可能的端点
        for(int i = 0; i < numend; i++)
        {
            for(int j = 0; j < 9; j++)
            {
                // int r = end[i] / w + indeces[j][0], c = end[i] % w + indeces[j][1];
                // if(r < 0 || r >= h || c < 0 || c >= w) continue;
                // int idx = end[i] + indeces[j][2];
                int idx = end[i] + indeces[j][2]; 
                if(idx < 0 || idx >= pixels) continue;
                resset[setcnt][0] = idx;
                resset[setcnt++][1] = 0;
            }
        }
        // 左下角
        resset[setcnt][0] = (h-1)*w;
        resset[setcnt++][1] = 0;
        for(int i = 0; i < setcnt; i++)
        {
            int curr = getValue(resset[i][0]), maxdiff = 0;
            for(int j = 0; j < 9; j++)
            {
                int r = resset[i][0] / w + indeces[j][0], c = resset[i][0] % w + indeces[j][1];
                if(r < 0 || r >= h || c < 0 || c >= w) continue;
                int idx = resset[i][0] + indeces[j][2];
                // get value at idx
                int val = getValue(idx);
                int diff = val - curr;
                if(diff < 0) diff = -diff;
                if(diff > maxdiff) maxdiff = diff;
            }
            resset[i][1] = maxdiff;
        }
        // sort
        qsort(resset, setcnt, 2 * sizeof(int), cmp_func);
        resset[setcnt][0] = pixels; // sentinel
        resset[setcnt][1] = -1;
        printf("%d\n", w);
        for(int i = 0; i < setcnt; i++)
        {
            int start = i;
            while(resset[start][1] == resset[i+1][1]) i++;
            printf("%d %d\n", resset[start][1], resset[i+1][0] - resset[start][0]);
        }
        printf("0 0\n");
    }
    printf("0\n");
    return 0;
}

 

posted @ 2014-04-01 12:45  D3猎人  阅读(567)  评论(0编辑  收藏  举报