IOI 2013
IOI 2013

Art Class

Given an image (2D grid of RGB pixels), classify it into one of four categories: Class 1: Modern/abstract art (few colors, large uniform regions) Class 2: Paintings with distinct objects (moderate variation) Class 3:...

Updated May 21, 2026
Track IOI
Year 2013
Statement Rendered from TeX
TeXC++Rendered statement

Problem Statement

Rendered from the "Problem Summary" section in the LaTeX write-up.

Given an image (2D grid of RGB pixels), classify it into one of four categories:

  1. Class 1: Modern/abstract art (few colors, large uniform regions)

  2. Class 2: Paintings with distinct objects (moderate variation)

  3. Class 3: Impressionist/textured paintings (high local variation)

  4. Class 4: Landscape/nature photographs (moderate to high detail)

  5. This is a heuristic/machine learning problem. No exact algorithm is specified; you must achieve a reasonable classification accuracy.

Editorial

The solution write-up is rendered from the LaTeX source, with equations kept live through MathJax.

Solution Approach

Use simple image features:

  1. Color variance: Compute the variance of R, G, B channels globally. Low variance suggests Class 1 (uniform colors).

  2. Edge density: Compute the average absolute difference between adjacent pixels. Low edge density suggests large uniform regions (Class 1), very high suggests Class 3.

  3. Green ratio: High green content suggests landscapes (Class 4).

  4. Saturation: High saturation with high variance suggests impressionist (Class 3).

  5. Decision rules:

  • If edge density is very low and color variance is low: Class 1.

  • If green ratio is high and edge density is moderate: Class 4.

  • If edge density is very high: Class 3.

  • Otherwise: Class 2.

Complexity

  • Time: $O(H \times W)$ (single pass over all pixels).

  • Space: $O(H \times W)$

C++ Solution

#include <bits/stdc++.h>
using namespace std;

int style(int H, int W, int R[500][500], int G[500][500], int B[500][500]){
    // Compute average color
    double avgR = 0, avgG = 0, avgB = 0;
    for(int i = 0; i < H; i++){
        for(int j = 0; j < W; j++){
            avgR += R[i][j];
            avgG += G[i][j];
            avgB += B[i][j];
        }
    }
    int total = H * W;
    avgR /= total; avgG /= total; avgB /= total;

    // Compute color variance
    double varR = 0, varG = 0, varB = 0;
    for(int i = 0; i < H; i++){
        for(int j = 0; j < W; j++){
            varR += (R[i][j] - avgR) * (R[i][j] - avgR);
            varG += (G[i][j] - avgG) * (G[i][j] - avgG);
            varB += (B[i][j] - avgB) * (B[i][j] - avgB);
        }
    }
    varR /= total; varG /= total; varB /= total;
    double totalVar = varR + varG + varB;

    // Compute edge density (average absolute difference with neighbors)
    double edgeSum = 0;
    int edgeCount = 0;
    for(int i = 0; i < H; i++){
        for(int j = 0; j < W - 1; j++){
            edgeSum += abs(R[i][j] - R[i][j+1]) + abs(G[i][j] - G[i][j+1])
                     + abs(B[i][j] - B[i][j+1]);
            edgeCount++;
        }
    }
    for(int i = 0; i < H - 1; i++){
        for(int j = 0; j < W; j++){
            edgeSum += abs(R[i][j] - R[i+1][j]) + abs(G[i][j] - G[i+1][j])
                     + abs(B[i][j] - B[i+1][j]);
            edgeCount++;
        }
    }
    double edgeDensity = edgeSum / edgeCount;

    // Green ratio
    double greenRatio = avgG / (avgR + avgG + avgB + 1);

    // Classification heuristic
    if(totalVar < 1000 && edgeDensity < 15){
        return 1; // Modern art: few colors, uniform regions
    }
    if(edgeDensity > 60){
        return 3; // Impressionist: very textured
    }
    if(greenRatio > 0.38 && totalVar > 2000){
        return 4; // Landscape: lots of green, varied
    }
    if(edgeDensity < 25 && totalVar < 3000){
        return 1;
    }
    if(edgeDensity > 40){
        return 3;
    }
    if(greenRatio > 0.35){
        return 4;
    }
    return 2; // Default: standard painting
}

int main(){
    int H, W;
    cin >> H >> W;
    int R[500][500], G[500][500], B[500][500];
    for(int i = 0; i < H; i++)
        for(int j = 0; j < W; j++)
            cin >> R[i][j] >> G[i][j] >> B[i][j];
    cout << style(H, W, R, G, B) << "\n";
    return 0;
}

Note: This is a heuristic solution. The thresholds were chosen empirically. More sophisticated approaches would use trained classifiers, but this demonstrates the feature-extraction approach suitable for a competition setting.

Code

C++ solution used for this page.

C++

Clean code view with a raw-file link when you want the original source.

Raw file
#include <bits/stdc++.h>
using namespace std;

int style(int H, int W, int R[500][500], int G[500][500], int B[500][500]){
    // Compute average color
    double avgR = 0, avgG = 0, avgB = 0;
    for(int i = 0; i < H; i++){
        for(int j = 0; j < W; j++){
            avgR += R[i][j];
            avgG += G[i][j];
            avgB += B[i][j];
        }
    }
    int total = H * W;
    avgR /= total; avgG /= total; avgB /= total;

    // Compute color variance
    double varR = 0, varG = 0, varB = 0;
    for(int i = 0; i < H; i++){
        for(int j = 0; j < W; j++){
            varR += (R[i][j] - avgR) * (R[i][j] - avgR);
            varG += (G[i][j] - avgG) * (G[i][j] - avgG);
            varB += (B[i][j] - avgB) * (B[i][j] - avgB);
        }
    }
    varR /= total; varG /= total; varB /= total;
    double totalVar = varR + varG + varB;

    // Compute edge density (average absolute difference with neighbors)
    double edgeSum = 0;
    int edgeCount = 0;
    for(int i = 0; i < H; i++){
        for(int j = 0; j < W - 1; j++){
            edgeSum += abs(R[i][j] - R[i][j+1]) + abs(G[i][j] - G[i][j+1])
                     + abs(B[i][j] - B[i][j+1]);
            edgeCount++;
        }
    }
    for(int i = 0; i < H - 1; i++){
        for(int j = 0; j < W; j++){
            edgeSum += abs(R[i][j] - R[i+1][j]) + abs(G[i][j] - G[i+1][j])
                     + abs(B[i][j] - B[i+1][j]);
            edgeCount++;
        }
    }
    double edgeDensity = edgeSum / edgeCount;

    // Green ratio
    double greenRatio = avgG / (avgR + avgG + avgB + 1);

    // Classification heuristic
    if(totalVar < 1000 && edgeDensity < 15){
        return 1; // Modern art: few colors, uniform regions
    }
    if(edgeDensity > 60){
        return 3; // Impressionist: very textured
    }
    if(greenRatio > 0.38 && totalVar > 2000){
        return 4; // Landscape: lots of green, varied
    }
    if(edgeDensity < 25 && totalVar < 3000){
        return 1;
    }
    if(edgeDensity > 40){
        return 3;
    }
    if(greenRatio > 0.35){
        return 4;
    }
    return 2; // Default: standard painting
}

int main(){
    int H, W;
    cin >> H >> W;
    int R[500][500], G[500][500], B[500][500];
    for(int i = 0; i < H; i++)
        for(int j = 0; j < W; j++)
            cin >> R[i][j] >> G[i][j] >> B[i][j];
    cout << style(H, W, R, G, B) << "\n";
    return 0;
}

Source Files and Assets

Raw files are still available here when you want the original TeX, C++, or statement assets.

Show raw files