zoukankan      html  css  js  c++  java
  • UVa12264 Risk(最大流)

    题目

    Source

    https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=3416

    Description

    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 Input

    2
    3
    1 1 0
    NYN
    YNY
    NYN
    7
    7 3 3 2 0 0 5
    NYNNNNN
    YNYYNNN
    NYNYYNN
    NYYNYNN
    NNYYNNN
    NNNNNNY
    NNNNNYN

    Sample Output

    1
    4

    分析

    题目大概说有N个点,有些被自己占了有些被敌人占了,然后这N个点有几个是相邻的。一开始己方点有几个士兵,一个回合中可以选择某几个己方点的士兵移动到相邻的己方的点,完成移动后要满足所有己方的点至少有一个士兵。问题要的是让边界点(与敌人占的点相邻的自己的点)中的最小值最大。

    最小值最大,显然二分。然后就二分+网络流搞了。

    值得说的是至少一个士兵的处理,可以直接对于各个点需要几个士兵向汇点连边,即边界点需要二分数值的士兵,而其他需要1个士兵;也可以一开始就把各点的士兵数都-1,也可以;或者最小费用最大流,不过画蛇添足。。

    其实这题题目意思感觉不清晰,反正搞过样例就差不多能A了吧。。另外UVa上的样例有点问题,我上面改了。

    代码

    #include<cstdio>
    #include<cstring>
    #include<queue>
    #include<algorithm>
    using namespace std;
    #define INF (1<<30)
    #define MAXN 222
    #define MAXM 222*222
    
    struct Edge{
        int v,cap,flow,next;
    }edge[MAXM];
    int vs,vt,NE,NV;
    int head[MAXN];
    
    void addEdge(int u,int v,int cap){
        edge[NE].v=v; edge[NE].cap=cap; edge[NE].flow=0;
        edge[NE].next=head[u]; head[u]=NE++;
        edge[NE].v=u; edge[NE].cap=0; edge[NE].flow=0;
        edge[NE].next=head[v]; head[v]=NE++;
    }
    
    int level[MAXN];
    int gap[MAXN];
    void bfs(){
        memset(level,-1,sizeof(level));
        memset(gap,0,sizeof(gap));
        level[vt]=0;
        gap[level[vt]]++;
        queue<int> que;
        que.push(vt);
        while(!que.empty()){
            int u=que.front(); que.pop();
            for(int i=head[u]; i!=-1; i=edge[i].next){
                int v=edge[i].v;
                if(level[v]!=-1) continue;
                level[v]=level[u]+1;
                gap[level[v]]++;
                que.push(v);
            }
        }
    }
    
    int pre[MAXN];
    int cur[MAXN];
    int ISAP(){
        bfs();
        memset(pre,-1,sizeof(pre));
        memcpy(cur,head,sizeof(head));
        int u=pre[vs]=vs,flow=0,aug=INF;
        gap[0]=NV;
        while(level[vs]<NV){
            bool flag=false;
            for(int &i=cur[u]; i!=-1; i=edge[i].next){
                int v=edge[i].v;
                if(edge[i].cap!=edge[i].flow && level[u]==level[v]+1){
                    flag=true;
                    pre[v]=u;
                    u=v;
                    //aug=(aug==-1?edge[i].cap:min(aug,edge[i].cap));
                    aug=min(aug,edge[i].cap-edge[i].flow);
                    if(v==vt){
                        flow+=aug;
                        for(u=pre[v]; v!=vs; v=u,u=pre[u]){
                            edge[cur[u]].flow+=aug;
                            edge[cur[u]^1].flow-=aug;
                        }
                        //aug=-1;
                        aug=INF;
                    }
                    break;
                }
            }
            if(flag) continue;
            int minlevel=NV;
            for(int i=head[u]; i!=-1; i=edge[i].next){
                int v=edge[i].v;
                if(edge[i].cap!=edge[i].flow && level[v]<minlevel){
                    minlevel=level[v];
                    cur[u]=i;
                }
            }
            if(--gap[level[u]]==0) break;
            level[u]=minlevel+1;
            gap[level[u]]++;
            u=pre[u];
        }
        return flow;
    }
    
    int n,a[111];
    char map[111][111];
    
    bool isOK(int k){
        vs=0; vt=2*n+1; NV=vt+1; NE=0;
        memset(head,-1,sizeof(head));
        int tot=0;
        for(int i=1; i<=n; ++i){
            if(a[i]==0) continue;
            addEdge(vs,i,a[i]);
            addEdge(i,i+n,INF);
    
            bool flag=0;
            for(int j=1; j<=n; ++j){
                if(map[i][j]=='N') continue;
                if(a[j]==0) flag=1;
                else addEdge(i,j+n,INF);
            }
    
            if(flag){
                addEdge(i+n,vt,k);
                tot+=k;
            }else{
                addEdge(i+n,vt,1);
                ++tot;
            }
        }
        return ISAP()==tot;
    }
    
    int main(){
        scanf("%*d");
        while(~scanf("%d",&n)){
            for(int i=1; i<=n; ++i){
                scanf("%d",a+i);
            }
            for(int i=1; i<=n; ++i){
                for(int j=1; j<=n; ++j){
                    scanf(" %c",&map[i][j]);
                }
            }
            int l=0,r=111111;
            while(l<r){
                int mid=l+r+1>>1;
                if(isOK(mid)) l=mid;
                else r=mid-1;
            }
            printf("%d
    ",l);
        }
        return 0;
    }
    
  • 相关阅读:
    ZOJ 3765 Lights (zju March I)伸展树Splay
    UVA 11922 伸展树Splay 第一题
    UVALive 4794 Sharing Chocolate DP
    ZOJ 3757 Alice and Bod 模拟
    UVALive 3983 捡垃圾的机器人 DP
    UVA 10891 SUM游戏 DP
    poj 1328 Radar Installatio【贪心】
    poj 3264 Balanced Lineup【RMQ-ST查询区间最大最小值之差 +模板应用】
    【转】RMQ-ST算法详解
    poj 3083 Children of the Candy Corn 【条件约束dfs搜索 + bfs搜索】【复习搜索题目一定要看这道题目】
  • 原文地址:https://www.cnblogs.com/WABoss/p/5758119.html
Copyright © 2011-2022 走看看