Problem:
MathJax.Hub.Config({ tex2jax: { inlineMath: [["$","$"], ["\\(","\\)"]], processEscapes: true }});

形状データ処理

コンピュータグラフィクスでは、三次元の形状を表現する方法として、ポリゴンモデルが使われます。ポリゴンモデルとは、頂点座標と、それらの頂点のつなぎ方を与えて面を作るモデルです。

一般のポリゴンモデルでは、任意の多角形を扱えますが、今回は三角形からなるポリゴンモデルを考えることにします。任意のポリゴンモデルは三角形を表す面情報の集まりとして表すことができます。

一つの面情報は、３つの頂点を並べて表します。ただし、並び方が異なるだけで同じ３点からなる場合は、同じ面情報を表すことにします。例えば、下図の四面体で、頂点１,２,３を繋いでできる面は、頂点２,３,１や、頂点３,２,１などのように表すこともできます。このように、同じ面情報が複数あると無駄になるので、１つにまとめてしまった方が良いでしょう。

面情報が与えられたとき、重複した面を無くすために消さなければならない面情報の個数を求めるプログラムを作成せよ。

Input

入力は以下の形式で与えられる。

N
p11 p12 p13
p21 p22 p23
:
pN1 pN2 pN3

１行目に、ポリゴンモデルの面情報の数 N (1 ≤ N ≤ 1000) が与えられる。続く N 行に、i 番目の面を作るために使う頂点の番号 pij (1 ≤ pij ≤ 1000) が与えられる。ただし、一つの面について、同じ頂点を２度以上使うことはない（pi1 ≠ pi2 かつ pi2 ≠ pi3 かつ pi1 ≠ pi3 である）。

Output

重複した面を無くすために消さなければならない面情報の個数を１行に出力する。

Sample Input 1

4
1 3 2
1 2 4
1 4 3
2 3 4

Sample Output 1

0

Sample Input 2

6
1 3 2
1 2 4
1 4 3
2 3 4
3 2 1
2 3 1

Sample Output 2

2

入出力例２では、１つ目と５つ目と６つ目の面は頂点1, 3, 2を使って三角形を作っていて、点の順番が異なるだけなので重複している。つまり、重複した面のうち２つの面を消せば重複した面は無くなる。

Solution in C# (judge verdict: Accepted)

using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO.Compression;
using System.IO.Pipes;
using System.Linq;
using System.Numerics;
using System.Security.Cryptography.X509Certificates;
using System.Text;
using static System.Console;
using static System.Math;

namespace AtCoder
{
    class Program
    {
        static void Main(string[] args)
        {
            var N = ReadInt();
            var list = new List<string>();
            var ans = 0;
            for (int i = 0; i < N; i++)
            {
                var p = ReadInts();
                Array.Sort(p);
                var s = string.Join("", p);
                if (list.Contains(s))
                {
                    ans++;
                }
                else
                {

                    list.Add(s);
                }
            }
            WriteLine(ans);
        }

        private static string Read() { return ReadLine(); }
        private static string[] Reads() { return (Read().Split()); }
        private static int ReadInt() { return int.Parse(Read()); }
        private static long ReadLong() { return long.Parse(Read()); }
        private static double ReadDouble() { return double.Parse(Read()); }
        private static int[] ReadInts() { return Array.ConvertAll(Read().Split(), int.Parse); }
        private static long[] ReadLongs() { return Array.ConvertAll(Read().Split(), long.Parse); }
        private static double[] ReadDoubles() { return Array.ConvertAll(Read().Split(), double.Parse); }
    }
}