(Analysis by Benjamin Qi)

There's a simple greedy strategy. Iterate over each grass square.

At the end, we add the number of distinct pairs in the set to the answer.

My code:

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

int main() {
	int N,M; cin >> N >> M;
	vector<string> G(N); for (string& row: G) cin >> row;
	auto exists_cow = [&](int i, int j) { 
		return 0 <= i && i < N && 0 <= j && j < M && G[i][j] == 'C';
	};
	set<vector<pair<int,int>>> pairs;
	int ans = 0;
	for (int i = 0; i < N; ++i) 
		for (int j = 0; j < M; ++j) if (G[i][j] == 'G') {
			vector<pair<int,int>> v;
			int dx[]{1,0,-1,0};
			int dy[]{0,1,0,-1};
			for (int d = 0; d < 4; ++d) {
				int ii = i+dx[d], jj = j+dy[d];
				if (exists_cow(ii,jj)) v.emplace_back(ii,jj);
			}
			if (v.size() > 2) {
				++ans;
				continue;
			}
			if (v.size() == 2) {
				sort(begin(v),end(v));
				pairs.insert(v);
			}
		}
	cout << pairs.size()+ans << "\n";
}

Danny Mittal's code (similar greedy strategy, but doesn't use a set):

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Arrays;
import java.util.StringTokenizer;
 
public class AcowdemiaIII {
 
    public static void main(String[] args) throws IOException {
        BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
        StringTokenizer tokenizer = new StringTokenizer(in.readLine());
        int n = Integer.parseInt(tokenizer.nextToken());
        int m = Integer.parseInt(tokenizer.nextToken());
        char[][] pasture = new char[n + 2][];
        pasture[0] = new char[m + 2];
        Arrays.fill(pasture[0], '.');
        pasture[n + 1] = pasture[0];
        for (int y = 1; y <= n; y++) {
            pasture[y] = ('.' + in.readLine() + '.').toCharArray();
        }
        int answer = 0;
        for (int y = 1; y <= n; y++) {
            for (int x = 1; x <= m; x++) {
                if (pasture[y][x] == 'G' && ((pasture[y][x - 1] == 'C' && pasture[y][x + 1] == 'C') || (pasture[y - 1][x] == 'C' && pasture[y + 1][x] == 'C'))) {
                    pasture[y][x] = '.';
                    answer++;
                }
            }
        }
        for (int y = 1; y <= n; y++) {
            for (int x = 1; x <= m; x++) {
                if (pasture[y][x] == 'C') {
                    if (pasture[y + 1][x - 1] == 'C') {
                        if (pasture[y][x - 1] == 'G') {
                            pasture[y][x - 1] = '.';
                            answer++;
                        } else if (pasture[y + 1][x] == 'G') {
                            pasture[y + 1][x] = '.';
                            answer++;
                        }
                    }
                    if (pasture[y + 1][x + 1] == 'C') {
                        if (pasture[y][x + 1] == 'G') {
                            pasture[y][x + 1] = '.';
                            answer++;
                        } else if (pasture[y + 1][x] == 'G') {
                            pasture[y + 1][x] = '.';
                            answer++;
                        }
                    }
                }
            }
        }
        System.out.println(answer);
    }
}