Skip to Content

Bovine Genomics

Solución en video

Por Jay Fu

Video de YouTube (hKBMRogNo0o)

Código de la solución en video
#include <cmath> #include <fstream> #include <iostream> using namespace std; int N, M; string spotty[500], plain[500]; int S[500][50], P[500][50], A[64]; // comprueba si el conjunto de posiciones j1,j2,j3 basta para explicar las manchas bool test_location(int j1, int j2, int j3) { bool good = true; // marcamos los valores de A usados por una vaca con manchas for (int i = 0; i < N; i++) A[S[i][j1] * 16 + S[i][j2] * 4 + S[i][j3]] = 1; // vemos si una vaca lisa tiene los mismos valores que una vaca con manchas for (int i = 0; i < N; i++) if (A[P[i][j1] * 16 + P[i][j2] * 4 + P[i][j3]]) good = false; // reiniciamos int [] A for (int i = 0; i < N; i++) A[S[i][j1] * 16 + S[i][j2] * 4 + S[i][j3]] = 0; return good; } int main(void) { ifstream fin("cownomics.in"); ofstream fout("cownomics.out"); fin >> N >> M; // leemos la entrada // convertimos letras de String [] spotty a números en int [][] S for (int i = 0; i < N; i++) { fin >> spotty[i]; for (int j = 0; j < M; j++) { if (spotty[i][j] == 'A') S[i][j] = 0; if (spotty[i][j] == 'C') S[i][j] = 1; if (spotty[i][j] == 'G') S[i][j] = 2; if (spotty[i][j] == 'T') S[i][j] = 3; } } // leemos la entrada // convertimos letras de String [] plain a números en int [][] P for (int i = 0; i < N; i++) { fin >> plain[i]; for (int j = 0; j < M; j++) { if (plain[i][j] == 'A') P[i][j] = 0; if (plain[i][j] == 'C') P[i][j] = 1; if (plain[i][j] == 'G') P[i][j] = 2; if (plain[i][j] == 'T') P[i][j] = 3; } } int answer = 0; // probamos cada conjunto posible de tres posiciones distintas para ver si puede // explicar las manchas for (int j1 = 0; j1 < M; j1++) for (int j2 = j1 + 1; j2 < M; j2++) for (int j3 = j2 + 1; j3 < M; j3++) if (test_location(j1, j2, j3)) answer++; fout << answer << "\n"; return 0; }
import java.io.BufferedReader; import java.io.FileReader; import java.io.IOException; import java.io.PrintWriter; import java.util.StringTokenizer; public class cownomicsSilver { static String[] spotty, plain; static int N, M; static int[][] S, P; static int[] A; // comprueba si el conjunto de posiciones j1,j2,j3 basta para explicar las manchas static boolean test_location(int j1, int j2, int j3) { boolean good = true; // marcamos los valores de A usados por una vaca con manchas for (int i = 0; i < N; i++) A[S[i][j1] * 16 + S[i][j2] * 4 + S[i][j3]] = 1; // vemos si una vaca lisa tiene los mismos valores que una vaca con manchas for (int i = 0; i < N; i++) if (A[P[i][j1] * 16 + P[i][j2] * 4 + P[i][j3]] == 1) good = false; // reiniciamos int [] A for (int i = 0; i < N; i++) A[S[i][j1] * 16 + S[i][j2] * 4 + S[i][j3]] = 0; return good; } public static void main(String[] args) throws IOException { BufferedReader br = new BufferedReader(new FileReader("cownomics.in")); PrintWriter out = new PrintWriter("cownomics.out"); StringTokenizer s = new StringTokenizer(br.readLine()); N = Integer.parseInt(s.nextToken()); M = Integer.parseInt(s.nextToken()); spotty = new String[500]; plain = new String[500]; S = new int[500][50]; P = new int[500][50]; A = new int[64]; // leemos la entrada // convertimos letras de String [] spotty a números en int [][] S for (int i = 0; i < N; i++) { spotty[i] = br.readLine(); for (int j = 0; j < M; j++) { if (spotty[i].charAt(j) == 'A') S[i][j] = 0; if (spotty[i].charAt(j) == 'C') S[i][j] = 1; if (spotty[i].charAt(j) == 'G') S[i][j] = 2; if (spotty[i].charAt(j) == 'T') S[i][j] = 3; } } // leemos la entrada // convertimos letras de String [] plain a números en int [][] P for (int i = 0; i < N; i++) { plain[i] = br.readLine(); for (int j = 0; j < M; j++) { if (plain[i].charAt(j) == 'A') P[i][j] = 0; if (plain[i].charAt(j) == 'C') P[i][j] = 1; if (plain[i].charAt(j) == 'G') P[i][j] = 2; if (plain[i].charAt(j) == 'T') P[i][j] = 3; } } int answer = 0; // probamos cada conjunto posible de tres posiciones distintas para ver si puede // explicar las manchas for (int j1 = 0; j1 < M; j1++) { for (int j2 = j1 + 1; j2 < M; j2++) { for (int j3 = j2 + 1; j3 < M; j3++) { if (test_location(j1, j2, j3)) answer++; } } } out.println(answer); out.close(); } }

Editorial oficial (C++) 

Explicación

Hay que recorrer todos los conjuntos posibles de 3 posiciones distintas.

Para cada conjunto de posiciones, recorremos todas las vacas con manchas y guardamos su patrón de genes en esas tres posiciones como un entero.

La forma de hacerlo es interpretar el patrón como un entero en base 4. Si mapeamos A a 0, T a 1, C a 2 y G a 3, el patrón de genes CTG sería el número en base 4 213213 (o 32+4+3=3932 + 4 + 3 = 39 en base 10).

La ventaja de este enfoque es que nos permite comprobar rápidamente si dos vacas tienen el mismo patrón sin hacer una comparación directa de strings.

Luego recorremos las vacas sin manchas y creamos los enteros de la misma forma. Si algún entero aparece tanto en una vaca lisa como en una vaca con manchas, entonces el conjunto actual de posiciones no es válido. En caso contrario, podemos sumar uno a la respuesta.

Implementación

Complejidad temporal O(NM3)\mathcal{O}(NM^3)

#include <fstream> #include <iostream> #include <map> #include <string> #include <vector> using std::cout; using std::endl; using std::vector; const std::map<char, int> GENOME_ID{{'A', 0}, {'T', 1}, {'C', 2}, {'G', 3}}; int main() { std::ifstream read("cownomics.in"); int cow_num; int genome_len; read >> cow_num >> genome_len; vector<vector<int>> spotted(cow_num, vector<int>(genome_len)); for (int s = 0; s < cow_num; s++) { std::string genome; read >> genome; for (int g = 0; g < genome_len; g++) { // A -> 0, C -> 1, T -> 2, G -> 3 spotted[s][g] = GENOME_ID.at(genome[g]); } } vector<vector<int>> plain(cow_num, vector<int>(genome_len)); for (int p = 0; p < cow_num; p++) { std::string genome; read >> genome; for (int g = 0; g < genome_len; g++) { plain[p][g] = GENOME_ID.at(genome[g]); } } int valid_sets = 0; // Recorremos cada grupo posible de 3. for (int a = 0; a < genome_len; a++) { for (int b = a + 1; b < genome_len; b++) { for (int c = b + 1; c < genome_len; c++) { vector<bool> spotted_ids(64); for (int sc = 0; sc < cow_num; sc++) { /* * Al multiplicar el primer, segundo y * tercer dígito por 16, 4 y 1 respectivamente, obtenemos * un número único para esa combinación. */ int total = (spotted[sc][a] * 16 + spotted[sc][b] * 4 + spotted[sc][c] * 1); spotted_ids[total] = true; } bool valid = true; for (int pc = 0; pc < cow_num; pc++) { int total = (plain[pc][a] * 16 + plain[pc][b] * 4 + plain[pc][c] * 1); // No podemos distinguir las vacas con manchas de las lisas. if (spotted_ids[total]) { valid = false; break; } } valid_sets += valid; } } } std::ofstream("cownomics.out") << valid_sets << endl; }
import java.io.*; import java.util.*; public class BovineGenomics { static final Map<Character, Integer> GENOME_ID = Map.ofEntries( Map.entry('A', 0), Map.entry('T', 1), Map.entry('C', 2), Map.entry('G', 3)); public static void main(String[] args) throws IOException { Kattio io = new Kattio("cownomics"); int cowNum = io.nextInt(); int genomeLen = io.nextInt(); int[][] spotted = new int[cowNum][genomeLen]; for (int s = 0; s < cowNum; s++) { String genome = io.next(); for (int g = 0; g < genomeLen; g++) { // A -> 0, C -> 1, T -> 2, G -> 3 spotted[s][g] = GENOME_ID.get(genome.charAt(g)); } } int[][] plain = new int[cowNum][genomeLen]; for (int p = 0; p < cowNum; p++) { String genome = io.next(); for (int g = 0; g < genomeLen; g++) { plain[p][g] = GENOME_ID.get(genome.charAt(g)); } } int validSets = 0; // Recorremos cada grupo posible de 3. for (int a = 0; a < genomeLen; a++) { for (int b = a + 1; b < genomeLen; b++) { for (int c = b + 1; c < genomeLen; c++) { boolean[] spottedIDs = new boolean[64]; for (int sc = 0; sc < cowNum; sc++) { /* * Al multiplicar el primer, segundo y * tercer dígito por 16, 4 y 1 respectivamente, obtenemos * un número único para esa combinación. */ int total = (spotted[sc][a] * 16 + spotted[sc][b] * 4 + spotted[sc][c] * 1); spottedIDs[total] = true; } boolean valid = true; for (int pc = 0; pc < cowNum; pc++) { int total = (plain[pc][a] * 16 + plain[pc][b] * 4 + plain[pc][c] * 1); // No podemos distinguir las vacas con manchas de las lisas. if (spottedIDs[total]) { valid = false; break; } } validSets += valid ? 1 : 0; } } } io.println(validSets); io.close(); } // CodeSnip{Kattio} }
GENOME_ID = {"A": 0, "T": 1, "C": 2, "G": 3} with open("cownomics.in") as read: cow_num, genome_len = [int(i) for i in read.readline().split()] spotted = [] for _ in range(cow_num): genome_str = read.readline() genome = [] for g in range(genome_len): # A -> 0, C -> 1, T -> 2, G -> 3 genome.append(GENOME_ID[genome_str[g]]) spotted.append(genome) plain = [] for _ in range(cow_num): genome_str = read.readline() genome = [] for g in range(genome_len): genome.append(GENOME_ID[genome_str[g]]) plain.append(genome) valid_sets = 0 for a in range(genome_len): for b in range(a + 1, genome_len): for c in range(b + 1, genome_len): spotted_ids = [False for _ in range(64)] for sc in range(cow_num): total = spotted[sc][a] * 16 + spotted[sc][b] * 4 + spotted[sc][c] * 1 spotted_ids[total] = True for pc in range(cow_num): total = plain[pc][a] * 16 + plain[pc][b] * 4 + plain[pc][c] * 1 if spotted_ids[total]: break else: valid_sets += 1 print(valid_sets, file=open("cownomics.out", "w"))