Solução Cavalos

Solução por Rogério Júnior

Vejamos o tabuleiro como um grafo em que as casas são vértices, e dois vértices estão ligados se as casas que eles representam são casas em que um cavalo pode ir, em um movimento, de uma para a outra.

Imagine agora uma componente conexa desse grafo. Note que ela é bipartida, visto que casas pretas só se ligam a casas brancas (pois um cavalo sempre muda a cor da casa em que está ao realizar um movimento). Desse modo, nesta componente, temos duas opções: ou colocamos cavalos em todas as casas preta ou em todas as casas brancas, basta escolhermos as que aparecem em maior quantidade!

De maneira geral, para cada componente conexa do grafo, vamos biparti-la em dois subconjuntos e adicionar à resposta o  número de vértices que aparecem no maior conjunto, pois podemos colocar um cavalo em cada casa dessas. Note que, por definição, dois cavalos do mesmo conjunto não se atacam (pois o grafo e bipartido!).

O algoritmo de bipartição de um grafo é simples: basta usarmos uma DFS. Quando chamamos a DFS para um determinado vértice, pintamos cada um de seus vizinhos da cor diferente da sua e chamamos a DFS para cada um deles. Segue o código para melhor entendimento:


#include <cstdio>
#include <algorithm>
using namespace std;
#define MAXN 1010
int m, n, cor[MAXN][MAXN], cor1, cor2, resp;
// DFS para bipartirmos o tabuleiro
void dfs(int i, int j){
// suponha que um cavalo está na casa i, j do tabuleiro
int i_=i+1, j_=j+2;
// para cada casa que ele pode atacar que ainda não tenha cor
if(i_>=1 and i_<=n and j_>=1 and j_<=m and !cor[i_][j_]){
// a colorimos de uma cor oposta à da casa original
// lembrando de atualizar as quantidades de casas de cada cor
if(cor[i][j]==1){
cor[i_][j_]=2;
cor2++;
}
else{
cor[i_][j_]=1;
cor1++;
}
// e chamo a DFS para essa casa
dfs(i_,j_);
}
// repito o processo com cada casa que o cavalo alcança
i_=i+1, j_=j-2;
if(i_>=1 and i_<=n and j_>=1 and j_<=m and !cor[i_][j_]){
if(cor[i][j]==1){
cor[i_][j_]=2;
cor2++;
}
else{
cor[i_][j_]=1;
cor1++;
}
dfs(i_,j_);
}
i_=i-1, j_=j+2;
if(i_>=1 and i_<=n and j_>=1 and j_<=m and !cor[i_][j_]){
if(cor[i][j]==1){
cor[i_][j_]=2;
cor2++;
}
else{
cor[i_][j_]=1;
cor1++;
}
dfs(i_,j_);
}
i_=i-1, j_=j-2;
if(i_>=1 and i_<=n and j_>=1 and j_<=m and !cor[i_][j_]){
if(cor[i][j]==1){
cor[i_][j_]=2;
cor2++;
}
else{
cor[i_][j_]=1;
cor1++;
}
dfs(i_,j_);
}
i_=i+2, j_=j+1;
if(i_>=1 and i_<=n and j_>=1 and j_<=m and !cor[i_][j_]){
if(cor[i][j]==1){
cor[i_][j_]=2;
cor2++;
}
else{
cor[i_][j_]=1;
cor1++;
}
dfs(i_,j_);
}
i_=i+2, j_=j-1;
if(i_>=1 and i_<=n and j_>=1 and j_<=m and !cor[i_][j_]){
if(cor[i][j]==1){
cor[i_][j_]=2;
cor2++;
}
else{
cor[i_][j_]=1;
cor1++;
}
dfs(i_,j_);
}
i_=i-2, j_=j+1;
if(i_>=1 and i_<=n and j_>=1 and j_<=m and !cor[i_][j_]){
if(cor[i][j]==1){
cor[i_][j_]=2;
cor2++;
}
else{
cor[i_][j_]=1;
cor1++;
}
dfs(i_,j_);
}
i_=i-2, j_=j-1;
if(i_>=1 and i_<=n and j_>=1 and j_<=m and !cor[i_][j_]){
if(cor[i][j]==1){
cor[i_][j_]=2;
cor2++;
}
else{
cor[i_][j_]=1;
cor1++;
}
dfs(i_,j_);
}
}
int main(){
// leio os valores de m e n
scanf("%d %d", &m, &n);
// para cada casa do tabuleiro
for(int i=1; i<=n; i++)
for(int j=1; j<=m; j++){
// se ela já tiver sido colorida, continuo
if(cor[i][j]) continue;
// caso contrário, a pinto da cor 1
cor[i][j]=cor1=1;
// chamo a DFS nela
dfs(i,j);
// e adicioniono a resp a quantidade de casas pintadas
// da cor que mais apareceu na bipartição do grafo
resp+=max(cor1,cor2);
// e zero as quantidades de casas de cada cor
// para as próximas bipartições
cor1=cor2=0;
}
// por fim, imprimo o valor salvo em resp
printf("%d\n", resp);
return 0;
}

view raw

cavalos.cpp

hosted with ❤ by GitHub