网络流 UVA 12264 Risk

来源:互联网 发布:唱谱软件安卓版 编辑:程序博客网 时间:2024/06/07 23:56

F  Risk

Risk is a board game played on a world map. This world is divided into regions by borders. Each region is controlled by a player (either you or one of your opponents). Any region that you control contains a positive number of your armies.
In each turn, you are allowed to move your armies. Each of your armies may either stay where it is, or move from a region to a bordering region under your control. The movements are performed one by one, in an order of your choice. At all times, each region must contain at least one army.
For strategic purposes, it is important to move your armies to regions that border your opponents' regions and minimize the number of armies on your regions that are totally surrounded by other regions under your control. You want your weakest link, i.e., the border region with the minimum number of armies, to be as strong as possible. What is the maximum number of armies that can be placed on it after one turn?

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'.
In every test case, you control at least one region, and your opponents control at least one region. Furthermore, at least one of your regions borders at least one of your opponents' regions.

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

InputOutput
231 1 0NYNYNYNYN77 3 3 2 0 0 5NYNNNNNYNYYNNNNYNYYNNNYYNYNNNNYYNNNNNNNNNYNNNNNYN
14


思路:把每个点拆成两个点,一个入度,一个出度,入度向自己的和每个相邻的点的出度连一条边,容量是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 longusing namespace std;#define eps 1e-7const 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();    }}



0 0