#include <iostream>
#include <vector>
using namespace std;
long maxFlow = 0, startSum = 0, targetSum = 0;
class Graph;
class Edge;
int valence(char atom);
int findBackEdge(Graph *G, Edge edge);
class Edge {
public:
int from;
int to;
int flow;
Edge(int from=-1, int to=-1, int flow=0);
};
class Graph {
public:
int v_num;
int height;
int width;
vector<bool> checked;
vector<vector<Edge> > edge;
Graph(int height, int width);
void addEdge(int from, int to, int flow);
void init(int height, int width);
void uncheckAll();
int toVertNum(int i, int j);
};
Graph::Graph(int height, int width) {
this->height = height;
this->width = width;
this->v_num = height * width + 2;
checked.resize(v_num, false);
edge.resize(v_num);
}
int findBackEdge(Graph *G, Edge edge) {
for(int child = 0; child < G->edge[edge.to].size(); ++child)
if(G->edge[edge.to][child].to == edge.from) {
return child;
}
return -1;
}
int valence(char atom) {
switch(atom) {
case('H'):
return 1;
case('O'):
return 2;
case('N'):
return 3;
case('C'):
return 4;
}
return 0;
}
void Graph::addEdge(int from, int to, int flow = 1) {
edge[from].push_back(
Edge(from, to, flow)
);
}
void Graph::uncheckAll() {
for(int i=0; i < v_num; ++i)
checked[i] = false;
}
int Graph::toVertNum(int i, int j) {
return i * width + j + 1;
}
void Graph::init(int height, int width) {
for (int i = 0; i < height; i++)
for (int j = 0; j < width; j++) {
char atom;
cin >> atom;
if ( (i%2 + j%2)%2 == 0 ) {
addEdge(0, toVertNum(i,j), valence(atom));
startSum += valence(atom);
if (i + 1 < height)
addEdge (toVertNum(i,j), toVertNum(i+1,j));
if (j + 1 < width)
addEdge (toVertNum(i,j), toVertNum(i,j+1));
if (i - 1 >= 0)
addEdge (toVertNum(i,j), toVertNum(i-1,j));
if (j - 1 >= 0)
addEdge (toVertNum(i,j), toVertNum(i,j-1));
}
else {
addEdge(toVertNum(i,j), v_num - 1, valence(atom));
targetSum += valence(atom);
}
}
}
Edge::Edge(int from, int to, int flow) {
this->from = from;
this->to = to;
this->flow = flow;
}
int tryPushFlow(Graph *G, int current = 0, int capacity = 5) {
G->checked[current] = true;
if(current == G->v_num-1) {
maxFlow += capacity;
return capacity;
}
for(int e=0; e < G->edge[current].size(); ++e) {
Edge edge = G->edge[current][e];
if(G->checked[edge.to] || edge.flow == 0)
continue;
int minCapacity = tryPushFlow(G, edge.to, min(edge.flow, capacity));
if(minCapacity > 0) {
G->edge[current][e].flow -= minCapacity;
int backEdgeNum = findBackEdge(G, edge);
if (backEdgeNum != -1)
G->edge[edge.to][backEdgeNum].flow += minCapacity;
else
G->edge[edge.to].push_back(Edge(edge.to, current, minCapacity));
return minCapacity;
}
}
return 0;
}
int main() {
int height, width;
cin >> height >> width;
Graph G = Graph(height, width);
G.init(height, width);
while(tryPushFlow(&G))
G.uncheckAll();
(maxFlow == startSum) && (maxFlow == targetSum) && (maxFlow != 0) ?
cout << "Valid" : cout << "Invalid";
}
I2luY2x1ZGUgPGlvc3RyZWFtPgojaW5jbHVkZSA8dmVjdG9yPgp1c2luZyBuYW1lc3BhY2Ugc3RkOwogCmxvbmcgbWF4RmxvdyA9IDAsIHN0YXJ0U3VtID0gMCwgdGFyZ2V0U3VtID0gMDsKIApjbGFzcyBHcmFwaDsKY2xhc3MgRWRnZTsKaW50IHZhbGVuY2UoY2hhciBhdG9tKTsKaW50IGZpbmRCYWNrRWRnZShHcmFwaCAqRywgRWRnZSBlZGdlKTsKIApjbGFzcyBFZGdlIHsKcHVibGljOgogICAgaW50IGZyb207CiAgICBpbnQgdG87CiAgICBpbnQgZmxvdzsKIAogICAgRWRnZShpbnQgZnJvbT0tMSwgaW50IHRvPS0xLCBpbnQgZmxvdz0wKTsKfTsKIApjbGFzcyBHcmFwaCB7CiAKcHVibGljOgogICAgaW50IHZfbnVtOwogICAgaW50IGhlaWdodDsKICAgIGludCB3aWR0aDsKICAgIHZlY3Rvcjxib29sPiBjaGVja2VkOwogICAgdmVjdG9yPHZlY3RvcjxFZGdlPiA+IGVkZ2U7CiAKICAgIEdyYXBoKGludCBoZWlnaHQsIGludCB3aWR0aCk7CiAgICB2b2lkIGFkZEVkZ2UoaW50IGZyb20sIGludCB0bywgaW50IGZsb3cpOwogICAgdm9pZCBpbml0KGludCBoZWlnaHQsIGludCB3aWR0aCk7CiAgICB2b2lkIHVuY2hlY2tBbGwoKTsKICAgIGludCB0b1ZlcnROdW0oaW50IGksIGludCBqKTsKfTsKIApHcmFwaDo6R3JhcGgoaW50IGhlaWdodCwgaW50IHdpZHRoKSB7CiAgICB0aGlzLT5oZWlnaHQgPSBoZWlnaHQ7CiAgICB0aGlzLT53aWR0aCA9IHdpZHRoOwogICAgdGhpcy0+dl9udW0gPSBoZWlnaHQgKiB3aWR0aCArIDI7CiAgICBjaGVja2VkLnJlc2l6ZSh2X251bSwgZmFsc2UpOwogICAgZWRnZS5yZXNpemUodl9udW0pOwp9CiAKaW50IGZpbmRCYWNrRWRnZShHcmFwaCAqRywgRWRnZSBlZGdlKSB7CiAgICBmb3IoaW50IGNoaWxkID0gMDsgY2hpbGQgPCBHLT5lZGdlW2VkZ2UudG9dLnNpemUoKTsgKytjaGlsZCkKICAgICAgICBpZihHLT5lZGdlW2VkZ2UudG9dW2NoaWxkXS50byA9PSBlZGdlLmZyb20pIHsKICAgICAgICAgICAgcmV0dXJuIGNoaWxkOwogICAgICAgIH0KICAgIHJldHVybiAtMTsKfQogCmludCB2YWxlbmNlKGNoYXIgYXRvbSkgewogICAgc3dpdGNoKGF0b20pIHsKICAgICAgICBjYXNlKCdIJyk6CiAgICAgICAgICAgIHJldHVybiAxOwogICAgICAgIGNhc2UoJ08nKToKICAgICAgICAgICAgcmV0dXJuIDI7CiAgICAgICAgY2FzZSgnTicpOgogICAgICAgICAgICByZXR1cm4gMzsKICAgICAgICBjYXNlKCdDJyk6CiAgICAgICAgICAgIHJldHVybiA0OwogICAgfQogICAgcmV0dXJuIDA7Cn0KIAp2b2lkIEdyYXBoOjphZGRFZGdlKGludCBmcm9tLCBpbnQgdG8sIGludCBmbG93ID0gMSkgewogICAgZWRnZVtmcm9tXS5wdXNoX2JhY2soCiAgICAgICAgICAgIEVkZ2UoZnJvbSwgdG8sIGZsb3cpCiAgICAgICAgKTsKfQogCnZvaWQgR3JhcGg6OnVuY2hlY2tBbGwoKSB7CiAgICBmb3IoaW50IGk9MDsgaSA8IHZfbnVtOyArK2kpCiAgICAgICAgY2hlY2tlZFtpXSA9IGZhbHNlOwp9CiAKaW50IEdyYXBoOjp0b1ZlcnROdW0oaW50IGksIGludCBqKSB7CiAgICByZXR1cm4gaSAqIHdpZHRoICsgaiArIDE7Cn0KIAp2b2lkIEdyYXBoOjppbml0KGludCBoZWlnaHQsIGludCB3aWR0aCkgewogICAgZm9yIChpbnQgaSA9IDA7IGkgPCBoZWlnaHQ7IGkrKykKICAgICAgICBmb3IgKGludCBqID0gMDsgaiA8IHdpZHRoOyBqKyspIHsKICAgICAgICAgICAgY2hhciBhdG9tOwogICAgICAgICAgICBjaW4gPj4gYXRvbTsKICAgICAgICAgICAgaWYgKCAoaSUyICsgaiUyKSUyID09IDAgKSB7CiAgICAgICAgICAgICAgICBhZGRFZGdlKDAsIHRvVmVydE51bShpLGopLCB2YWxlbmNlKGF0b20pKTsKICAgICAgICAgICAgICAgIHN0YXJ0U3VtICs9IHZhbGVuY2UoYXRvbSk7CiAgICAgICAgICAgICAgICBpZiAoaSArIDEgPCBoZWlnaHQpCiAgICAgICAgICAgICAgICAgICAgYWRkRWRnZSAodG9WZXJ0TnVtKGksaiksIHRvVmVydE51bShpKzEsaikpOwogICAgICAgICAgICAgICAgaWYgKGogKyAxIDwgd2lkdGgpCiAgICAgICAgICAgICAgICAgICAgYWRkRWRnZSAodG9WZXJ0TnVtKGksaiksIHRvVmVydE51bShpLGorMSkpOwogICAgICAgICAgICAgICAgaWYgKGkgLSAxID49IDApCiAgICAgICAgICAgICAgICAgICAgYWRkRWRnZSAodG9WZXJ0TnVtKGksaiksIHRvVmVydE51bShpLTEsaikpOwogICAgICAgICAgICAgICAgaWYgKGogLSAxID49IDApCiAgICAgICAgICAgICAgICAgICAgYWRkRWRnZSAodG9WZXJ0TnVtKGksaiksIHRvVmVydE51bShpLGotMSkpOwogICAgICAgICAgICB9CiAgICAgICAgICAgIGVsc2UgewogICAgICAgICAgICAgICAgYWRkRWRnZSh0b1ZlcnROdW0oaSxqKSwgdl9udW0gLSAxLCB2YWxlbmNlKGF0b20pKTsKICAgICAgICAgICAgICAgIHRhcmdldFN1bSArPSB2YWxlbmNlKGF0b20pOwogICAgICAgICAgICB9CiAgICAgICAgfQp9CiAKRWRnZTo6RWRnZShpbnQgZnJvbSwgaW50IHRvLCBpbnQgZmxvdykgewogICAgdGhpcy0+ZnJvbSA9IGZyb207CiAgICB0aGlzLT50byA9IHRvOwogICAgdGhpcy0+ZmxvdyA9IGZsb3c7Cn0KIAppbnQgdHJ5UHVzaEZsb3coR3JhcGggKkcsIGludCBjdXJyZW50ID0gMCwgaW50IGNhcGFjaXR5ID0gNSkgewogICAgRy0+Y2hlY2tlZFtjdXJyZW50XSA9IHRydWU7CiAgICBpZihjdXJyZW50ID09IEctPnZfbnVtLTEpIHsKICAgICAgICBtYXhGbG93ICs9IGNhcGFjaXR5OwogICAgICAgIHJldHVybiBjYXBhY2l0eTsKICAgIH0KICAgIGZvcihpbnQgZT0wOyBlIDwgRy0+ZWRnZVtjdXJyZW50XS5zaXplKCk7ICsrZSkgewogICAgICAgIEVkZ2UgZWRnZSA9IEctPmVkZ2VbY3VycmVudF1bZV07CiAKICAgICAgICBpZihHLT5jaGVja2VkW2VkZ2UudG9dIHx8IGVkZ2UuZmxvdyA9PSAwKQogICAgICAgICAgICBjb250aW51ZTsKIAogICAgICAgIGludCBtaW5DYXBhY2l0eSA9IHRyeVB1c2hGbG93KEcsIGVkZ2UudG8sIG1pbihlZGdlLmZsb3csIGNhcGFjaXR5KSk7CiAgICAgICAgaWYobWluQ2FwYWNpdHkgPiAwKSB7CiAgICAgICAgICAgIEctPmVkZ2VbY3VycmVudF1bZV0uZmxvdyAtPSBtaW5DYXBhY2l0eTsKICAgICAgICAgICAgaW50IGJhY2tFZGdlTnVtID0gZmluZEJhY2tFZGdlKEcsIGVkZ2UpOwogICAgICAgICAgICBpZiAoYmFja0VkZ2VOdW0gIT0gLTEpCiAgICAgICAgICAgICAgICBHLT5lZGdlW2VkZ2UudG9dW2JhY2tFZGdlTnVtXS5mbG93ICs9IG1pbkNhcGFjaXR5OwogICAgICAgICAgICBlbHNlCiAgICAgICAgICAgICAgICBHLT5lZGdlW2VkZ2UudG9dLnB1c2hfYmFjayhFZGdlKGVkZ2UudG8sIGN1cnJlbnQsIG1pbkNhcGFjaXR5KSk7CiAgICAgICAgICAgIHJldHVybiBtaW5DYXBhY2l0eTsKICAgICAgICB9CiAgICB9CiAgICByZXR1cm4gMDsKfQogCmludCBtYWluKCkgewogICAgaW50IGhlaWdodCwgd2lkdGg7CiAgICBjaW4gPj4gaGVpZ2h0ID4+IHdpZHRoOwogICAgR3JhcGggRyA9IEdyYXBoKGhlaWdodCwgd2lkdGgpOwogICAgRy5pbml0KGhlaWdodCwgd2lkdGgpOwogCiAgICB3aGlsZSh0cnlQdXNoRmxvdygmRykpCiAgICAgICAgRy51bmNoZWNrQWxsKCk7CiAKICAgIChtYXhGbG93ID09IHN0YXJ0U3VtKSAmJiAobWF4RmxvdyA9PSB0YXJnZXRTdW0pICYmIChtYXhGbG93ICE9IDApID8KICAgIGNvdXQgPDwgIlZhbGlkIiA6IGNvdXQgPDwgIkludmFsaWQiOwp9