很明显是一道网络流的题
题目提到最小值最大化 就可以想到二分答案 然后判断是否满流即可
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
#include <vector>
using namespace std;
#define bug puts("....bug....")
const int maxn = 200 + 10;
const int N = 100 + 10;
const int INF = 1e9;
struct Edge{
int u, v, cap, flow;
Edge(){}
Edge(int u, int v, int cap, int flow) : u(u), v(v), cap(cap), flow(flow){}
};
struct ISAP{
int n, s, t;
int num[maxn], cur[maxn], d[maxn], p[maxn];
vector<int> G[maxn];
vector<Edge> edges;
void add(int u, int v, int cap){
edges.push_back(Edge(u, v, cap, 0));
edges.push_back(Edge(v, u, 0, 0));
int m = edges.size();
G[u].push_back(m-2);
G[v].push_back(m-1);
}
void init(int n){
this -> n = n;
for(int i = 0; i < n; i++) G[i].clear();
edges.clear();
}
void bfs(){
for(int i = 0; i < n; i++) d[i] = INF;
d[t] = 0;
queue<int> Q;
Q.push(t);
while(!Q.empty()){
int x = Q.front(); Q.pop();
for(int i = 0; i < G[x].size(); i++){
Edge &e = edges[G[x][i]];
if(e.cap > 0 || d[e.v] <= d[x] + 1) continue;
d[e.v] = d[x] + 1;
Q.push(e.v);
}
}
}
int augment(){
int x = t, a = INF;
while(x != s){
Edge &e = edges[p[x]];
a = min(a, e.cap - e.flow);
x = e.u;
}
x = t;
while(x != s){
edges[p[x]].flow += a;
edges[p[x]^1].flow -= a;
x = edges[p[x]].u;
}
return a;
}
int maxflow(int s, int t){
this -> s = s;
this -> t = t;
memset(cur, 0, sizeof(cur));
memset(num, 0, sizeof(num));
bfs();
for(int i = 0; i < n; i++) if(d[i] != INF) num[d[i]]++;
int x = s, flow = 0;
while(d[s] < n){//bug;
if(x == t){
flow += augment();
x = s;
}
int ok = 0;
for(int i = cur[x]; i < G[x].size(); i++){
Edge &e = edges[G[x][i]];
if(e.cap > e.flow && d[e.v] + 1 == d[x]){
ok = 1;
cur[x] = i;
p[e.v] = G[x][i];
x = e.v;
break;
}
}
if(!ok){
int m = n - 1;
for(int i = 0; i < G[x].size(); i++){
Edge &e = edges[G[x][i]];
if(e.cap > e.flow) m = min(m, d[e.v]);
}
if(--num[d[x]] == 0) break;
++num[d[x] = m + 1];
cur[x] = 0;
if(x != s) x = edges[p[x]].u;
}
}
return flow;
}
}solver;
int a[N], n, l, r, flow, S, T;
char map[N][N];
void input(){
scanf("%d", &n);
l = r = 0;
S = n * 2, T = n * 2 + 1;
for(int i = 0; i < n; i++){
scanf("%d", &a[i]); r += a[i];
}
for(int i = 0; i < n; i++) scanf("%s", map[i]);
}
void build(int mid){
flow = 0;
solver.init(n * 2 + 2);
for(int i = 0; i < n; i++){
solver.add(S, i * 2, a[i]);
solver.add(i * 2, i * 2 + 1, a[i]);
}
for(int i = 0; i < n; i++)if(a[i] > 0){
bool flag = false;
for(int j = 0; j < n; j++)if(map[i][j] == 'Y'){
if(a[j] > 0) {solver.add(i * 2, j * 2 + 1, INF);
}
else flag = true;
}
if(flag){
solver.add(i * 2 + 1, T, mid);
flow += mid;
}
else{
solver.add(i * 2 + 1, T, 1);
flow += 1;
}
}
}
void solve(){
int ans;
while(l <= r){
int mid = (l + r) / 2;
build(mid);
if(solver.maxflow(S,T) == flow){
ans = mid;
l = mid + 1;
}
else r = mid - 1;
}
printf("%d\n", ans);
}
int main()
{
// freopen("in.txt", "r", stdin);
int T;
scanf("%d", &T);
while(T--){
input();
solve();
}
return 0;
}