思路:把每个点拆成两个点,一个入度,一个出度,入度向自己的和每个相邻的点的出度连一条边,容量是ai,每个点出度连一条边到汇点,容量为1,那些与敌人相邻的点再多连一条边到汇点,容量是二分的值,我们只需要二分这个值,跑一下网络流,如果满流,表示可以,否则不行。
#include<bits/stdc++.h>
using namespace std;
const int inf = 0x7f7f7f7f;
const int maxn = 210;
const int maxm = maxn * maxn;
int head[maxn],pnt[maxm],nxt[maxm],flow[maxm],level[maxn];
int e;
queue<int> q;
void AddEdge(int u,int v,int f){
pnt[e]=v; nxt[e]=head[u]; flow[e]=f; head[u]=e++;
pnt[e]=u; nxt[e]=head[v]; flow[e]=0; head[v]=e++;
}
int st,des;
int n;
char mapp[maxn][maxn];
int a[maxn];
int Build(int val){
int sum=0;
memset(head,-1,sizeof(head));
e=st=0; des=2*n+1;
for(int i=1;i<=n;i++){
bool isborder = false;
if(!a[i]) continue;
AddEdge(st,i,a[i]);
AddEdge(i,i+n,a[i]);
for(int j=1;j<=n;j++){
if(mapp[i][j]=='Y'){
if(!a[j]) isborder = true;
else AddEdge(n+i,j,inf);
}
}
if(isborder){
AddEdge(i,des,val);
sum+=val;
}
else {
AddEdge(i,des,1);
sum+=1;
}
}
return sum;
}
bool BFS(){
memset(level,0,sizeof(level));
level[st]=1;
q.push(st);
while(!q.empty()){
int u=q.front();
q.pop();
for(int i=head[u];i!=-1;i=nxt[i]){
if(flow[i]&&!level[pnt[i]]){
level[pnt[i]]=level[u]+1;
q.push(pnt[i]);
}
}
}
return level[des];
}
int DFS(int u,int maxf){
if(u==des || !maxf){
return maxf;
}
for(int i=head[u],t;i!=-1;i=nxt[i])
if(level[pnt[i]]==level[u]+1&&(t=DFS(pnt[i],min(flow[i],maxf)))){
flow[i]-=t;;
flow[i^1]+=t;
return t;
}
return level[u]=0;
}
int maxflow()
{
int ans=0;
while(BFS()){
while(1){
int val=DFS(st,inf);
if(!val) break;
ans+=val;
}
}
return ans;
}
int main()
{
int t;
scanf("%d",&t);
while(t--){
scanf("%d",&n);
for(int i=1;i<=n;i++)
scanf("%d",&a[i]);
for(int i=1;i<=n;i++)
scanf("%s",mapp[i]+1);
int sl=0,sr=100010,ans=0;
while(sl<=sr){
int mid=(sl+sr)>>1;
int val=Build(mid);
int f=maxflow();
if(f==val){
sl=mid+1;
ans=mid;
}
else sr=mid-1;
}
printf("%d\n",ans);
}
return 0;
}