F Risk
Input
On the first line a positive integer: the number of test cases, at most 100. After that per test case:- One line with an integer n (1 ≤ n ≤ 100): the number of regions.
- One line with n integers ai (0 ≤ ai ≤ 100): the number of your armies on each region. A number 0 indicates that a region is controlled by your opponents, while a positive number indicates that it is under your control.
- n lines with n characters, where each character is either `Y' or `N'. The i-th character of the j-th line is `Y' if regions i and j border, and `N' otherwise. This relationship is symmetric and the i-th character of the i-th line will always be `N'.
Output
Per test case:- One line with an integer: the maximum number of armies on your weakest border region after one turn of moving.
Sample in- and output
Input | Output |
2 3 1 1 0 NYN YNY NYN 7 7 3 3 2 0 0 5 NYNNNNN YNYYNNN NYNYYNN NYYNYNN NNYYNNN NNNNNNY NNNNNYN | 1 4 |
思路:把每个点拆成两个点,一个入度,一个出度,入度向自己的和每个相邻的点的出度连一条边,容量是ai,每个点出度连一条边到汇点,容量为1,那些与敌人相邻的点再多连一条边到汇点,容量是二分的值,我们只需要二分这个值,跑一下网络流,如果满流,表示可以,否则不行。
代码:
#include <vector>
#include <list>
#include <map>
#include <set>
#include <queue>
#include <deque>
#include <string.h>
#include <stack>
#include <bitset>
#include <algorithm>
#include <functional>
#include <numeric>
#include <utility>
#include <sstream>
#include <iostream>
#include <iomanip>
#include <cstdio>
#include <cmath>
#include <cstdlib>
#include <ctime>
#define LL long long
using namespace std;
#define eps 1e-7
const int maxn=200+5;
const int inf=1e8;
struct Edge
{
int u,v,cap,flow;
Edge(int u,int v,int cap,int flow)
:u(u),v(v),cap(cap),flow(flow) { }
};
vector<Edge> edges;
vector<int> G[maxn];
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);
}
struct ISAP
{
int d[maxn], p[maxn], num[maxn], cur[maxn];
int n, s, t;
void init(int n) { this->n = n; }
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;
}
void bfs()
{
for (int i = 0; i<n; ++i) d[i] = inf;
queue<int> q;
d[t] = 0;
q.push(t);
while (q.size())
{
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 maxflow(int s, int t)
{
this->s = s, this->t = t;
memset(num, 0, sizeof(num));
memset(cur, 0, sizeof(cur));
bfs();
for (int i = 0; i<n; ++i)
if (d[i] != inf) ++num[d[i]];
int flow = 0, x = s;
while (d[s]<n)
{
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 n,s,t;
bool enm[maxn];
int a[maxn];
vector<int> bin;
int cnt,ctr;
inline int in(int x) { return (x<<1)-1; }
inline int out(int x) { return x<<1; }
void input()
{
scanf("%d",&n);
memset(enm,0,sizeof(enm));
edges.clear();
s=0; t=2*n+1; solver.init(t+1);
for(int i=0;i<maxn;++i) G[i].clear();
ctr=0;
for(int i=1;i<=n;++i) {
int x; scanf("%d",&x);
a[i]=x;
if(x==0) enm[i]=true;
else { add(s,in(i),x); add(in(i),out(i),x); add(out(i),t,1); ctr++; }
}
char s[110];
bin.clear(); cnt=0;
for(int i=1;i<=n;++i) {
scanf("%s",s+1);
if(enm[i]) continue;
bool near=false;
for(int j=1;j<=n;++j) {
if(s[j]=='N') continue;
if(enm[j]) near=true;
else add(in(i),out(j),a[i]);
}
if(near) { add(out(i),t,inf); int k=edges.size()-2; bin.push_back(k); ++cnt; }
}
}
void clear(int up)
{
for(int i=0;i<edges.size();++i) edges[i].flow=0;
for(int i=0;i<bin.size();++i) {
edges[bin[i]].cap=up;
}
}
bool ok(int up)
{
clear(up);
int flow=solver.maxflow(s,t);
return (up*cnt+ctr)==flow;
}
void solve()
{
int l=1,r=n*100,m;
int ans=0;
while(l<=r) {
m=(l+r)>>1;
if(ok(m)) {
ans=m;
l=m+1;
} else r=m-1;
}
++ans; printf("%d\n",ans);
}
int main()
{
int T;cin>>T;
while(T--) {
input();
solve();
}
}