Analysis: Liars and Truth Tellers by Travis Hance
#include <cstdio>
#include <cstring>
#define NMAX 1005
// For any positive C, cows labelled C or -C are in the same component.
// Either C's are truth tellers and -C's are liars, or other way around.
int components[NMAX];
int main() {
freopen("truth.in","r",stdin);
freopen("truth.out","w",stdout);
int n, m;
scanf("%d", &n);
scanf("%d", &m);
for (int i = 0; i < n; i++) {
components[i] = i+1;
}
for (int line = 0; line < m; line++) {
int a, b;
char c;
scanf("%d", &a);
scanf("%d", &b);
a--;
b--;
do {
c = fgetc(stdin);
} while (c != 'L' && c != 'T');
if (components[a] == components[b] || components[a] == -components[b]) {
// If a and b are in the same component, check that the newly added
// edge is consistent.
if ((components[a] == components[b]) ^ (c == 'T')) {
printf("%d\n", line);
return 0;
}
} else {
// If a and b are in different components, merge the two components,
// by finding everything in b's component and moving it to a's
// component.
int acomp = (c == 'T' ? components[a] : -components[a]);
int bcomp = components[b];
for (int i = 0; i < n; i++) {
if (components[i] == bcomp) {
components[i] = acomp;
} else if (components[i] == -bcomp) {
components[i] = -acomp;
}
}
}
}
printf("%d\n", m);
}
Here is a C++ solution implementing the binary search solution:
#include <cstdio>
#include <cstdlib>
#include <vector>
using namespace std;
#define NMAX 1005
#define MMAX 10005
// a type of 'true' indicates an 'L' edge, that is, the two
// relevant cows should be of different type
struct edge {
int dest;
bool type;
int index;
};
vector<edge> edges[NMAX];
int components[NMAX];
bool type[NMAX];
// DFS flood-fill, restricting to edges with indices at most
// nstatments
bool dfs(int v, int comp, bool t, int nstatements) {
if (components[v] != 0) {
return t == type[v];
}
components[v] = comp;
type[v] = t;
for (int i = 0; i < edges[v].size(); i++) {
if (edges[v][i].index < nstatements &&
!dfs(edges[v][i].dest, comp, edges[v][i].type ^ t, nstatements)) {
return false;
}
}
return true;
}
// Returns true if the first nstatements statements are consistent
bool consistent(int n, int nstatements) {
for (int i = 0; i < n; i++) {
components[i] = 0;
}
int nComponents = 0;
for (int i = 0; i < n; i++) {
if (components[i] == 0) {
nComponents++;
if (!dfs(i, nComponents, false, nstatements)) {
return false;
}
}
}
return true;
}
int main() {
freopen("truth.in","r",stdin);
freopen("truth.out","w",stdout);
int n, m;
scanf("%d", &n);
scanf("%d", &m);
for (int line = 0; line < m; line++) {
int a, b;
char c;
scanf("%d", &a);
scanf("%d", &b);
a--;
b--;
do {
c = fgetc(stdin);
} while (c != 'L' && c != 'T');
edge e;
e.type = (c == 'L');
e.index = line;
e.dest = b;
edges[a].push_back(e);
e.dest = a;
edges[b].push_back(e);
}
// binary search
// invariant: lo <= answer < hi
int lo = 1, hi = m+1;
while (lo + 1 < hi) {
int mid = (lo + hi) / 2;
if (consistent(n, mid)) {
lo = mid;
} else {
hi = mid;
}
}
printf("%d\n", lo);
}