public class DancingForever {
boolean[] getMinimalCut
(String x
) {
int n = 0;
while(n*n < x.length())
n++;
//1
//2+i
//2+n+i
//2+n+n
int S = 1, T = 2 + n + n;
networkFlow solver = new networkFlow();
solver.n = T;
solver.prepare();
int INF = 100000000;
for(int i = 0; i < n; i++)
{
solver.addedge(S, 2 + i, 1);
solver.addedge(2+n+i, T, 1);
}
for(int i = 0; i < n; i++)
for(int j = 0; j < n; j++)
if(x.charAt(n*i+j) == 'Y')
{
solver.addedge(2+i, 2+n+j, INF);
}
int flow = solver.maxFlow();
solver.augment(1, 1000000000);
boolean[] ret = new boolean[n];
for(int i = 0; i < n; i++)
ret[i] = (solver.visited[2+i]);
return ret;
}
int[] getMaximalMatching
(String x,
boolean[] able
) {
int n = 0;
while(n*n < x.length())
n ++;
//1
//2+i
//2+n+i
//2+n+n
int S = 1, T = 2 + n + n;
networkFlow solver = new networkFlow();
solver.n = T;
solver.prepare();
int INF = 100000000;
edge[][] edges = new edge[n][n];
for(int i = 0; i < n; i++)
{
solver.addedge(S, 2+i, 1);
solver.addedge(2+n+i, T, 1);
}
for(int i = 0; i < n; i++)
for(int j = 0; j < n; j++)
if(able[i] && x.charAt(n*i+j) == 'Y')
{
edges[i][j] = solver.addedge(2+i, 2+n+j, 1);
}
int flow = solver.maxFlow();
int[] ret = new int[flow*2];
int t = 0;
for(int i = 0; i < n; i++)
for(int j = 0; j < n; j++) {
if (edges[i][j] != null && edges[i][j].cap == 0) {
ret[t] = i;
t++;
ret[t] = j;
t++;
}
}
return ret;
}
public int[] getStablePairs
(String x
) {
int n = 0;
while(n*n < x.length())
n ++;
boolean[] able = new boolean[n];
for(int i = 0; i < n; i++)
able[i] = true;
int[] matching = getMaximalMatching(x, able);
System.
out.
println("Maxmatching = " + (matching.
length / 2) + " / " + n
); if(matching.length / 2 == n)
return matching;
able = getMinimalCut(x);
matching = getMaximalMatching(x, able);
return matching;
}
public class edge
{
int dest, cap;
edge next, pair;
edge(){dest = 0; cap = 0; next = null; pair = null;}
edge(int _dest, int _cap, edge _next){dest = _dest; cap = _cap; next = _next; pair = null;}
};
public class networkFlow
{
edge[] e;
int n, flow;
int[] pi;
void prepare()
{
e = new edge[n+1];
flow = 0;
pi = new int[n+1];
for(int i = 1; i <= n; i++)
{
pi[i] = 0;
visited[i] = false;
}
}
int augment(int w, int limit)
{
int t;
visited[w] = true;
if(w == n)
{
flow += limit;
return limit;
}
for(edge i = e[w]; i != null; i = i.next)
{
if(i.cap > 0 && visited[i.dest] == false && pi[w] == pi[i.dest] + 1)
{
t
= augment
(i.
dest,
Math.
min(limit, i.
cap)); if(t > 0)
{
i.cap -= t;
i.pair.cap += t;
return t;
}
}
}
return 0;
}
{
int t = 1000000000;
for(int i = 1; i <= n; i++)
if(visited[i] == true)
for(edge j = e[i]; j != null; j = j.next)
if(j.cap > 0 && visited[j.dest] == false)
t
= Math.
min(t, pi
[j.
dest] + 1 - pi
[i
]); if(t == 1000000000)
return false;
for(int i = 1; i <= n; i++)
if(visited[i] == true)
pi[i] += t;
return true;
}
edge addedge(int s, int t, int c)
{
//System.out.println(s + " -> " + t + " : " + c);
e[s] = new edge(t, c, e[s]);
e[t] = new edge(s, 0, e[t]);
e[s].pair = e[t];
e[t].pair = e[s];
return e[s];
}
int maxFlow()
{
do
{
do
{
for(int i = 1; i <= n; i++)
visited[i] = false;
}
while(augment(1, 1000000000) > 0);
}
while (fix());
return flow;
}
}
}