【BZOJ 1458】 士兵占领

1458: 士兵占领

Time Limit: 10 Sec Memory Limit: 64 MB

Submit: 632 Solved: 366

[Submit][Status][Discuss]

Description

有一个M * N的棋盘,有的格子是障碍。现在你要选择一些格子来放置一些士兵,一个格子里最多可以放置一个士兵,障碍格里不能放置士兵。我们称这些士兵占领了整个棋盘当满足第i行至少放置了Li个士兵, 第j列至少放置了Cj个士兵。现在你的任务是要求使用最少个数的士兵来占领整个棋盘。

Input

第一行两个数M, N, K分别表示棋盘的行数,列数以及障碍的个数。 第二行有M个数表示Li。 第三行有N个数表示Ci。 接下来有K行,每行两个数X, Y表示(X, Y)这个格子是障碍。

Output

输出一个数表示最少需要使用的士兵个数。如果无论放置多少个士兵都没有办法占领整个棋盘,输出”JIONG!” (不含引号)

Sample Input

4 4 4

1 1 1 1

0 1 0 3

1 4

2 2

3 3

4 3

Sample Output

4

数据范围

M, N <= 100, 0 <= K <= M * N

有源汇有上下界的最小流。

详见《有上下界的网络流问题

#include <iostream>
#include <algorithm>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#define M 500005
#include <queue>
#define inf 0x3f3f3f3f
using namespace std;
struct edge
{
    int from,to,cap,flow,ne;
}E[M];
int tot,h[M],d[M],s,t,cur[M],cant[105][105],v[M],n,m;
void Addedge(int from,int to,int cap)
{
    E[++tot]=(edge){from,to,cap,0,h[from]};
    h[from]=tot;
    E[++tot]=(edge){to,from,0,0,h[to]};
    h[to]=tot;
}
int bfs()
{
    for (int i=s;i<=t;i++)
        v[i]=0;
    v[s]=1;
    queue<int> q;
    q.push(s);
    d[s]=0;
    while (!q.empty())
    {
        int x=q.front();
        q.pop();
        for (int i=h[x];i;i=E[i].ne)
        {
            edge e=E[i];
            if (!v[e.to]&&e.cap>e.flow)
            {
                v[e.to]=1;
                d[e.to]=d[x]+1;
                q.push(e.to);
            }
        }
    }
    return v[t];
}
int dfs(int x,int a)
{
    if (x==t||!a) return a;
    int flow=0;
    for (int &i=cur[x];i;i=E[i].ne)
    {
        edge &e=E[i];
        if (d[e.to]!=d[x]+1) continue;
        int f=dfs(e.to,min(a,e.cap-e.flow));
        if (f>0)
        {
            flow+=f;
            a-=f;
            e.flow+=f;
            E[i^1].flow-=f;
            if (!a) break;
        }
    }
    return flow;
}
int dinic()
{
    int flow=0;
    while (bfs())
    {
        for (int i=s;i<=t;i++)
            cur[i]=h[i];
        flow+=dfs(s,inf);
    }
    return flow;
}
int main()
{
    tot=1;
    int k;
    scanf("%d%d%d",&n,&m,&k);
    int jud=0;
    int s1=n+m+1,t1=n+m+2;
    s=0,t=n+m+3;
    for (int i=1;i<=n;i++)
    {
        int x;
        scanf("%d",&x);
        jud+=x;
        Addedge(s1,i,m-x);
        Addedge(s,i,x),Addedge(s1,t,x);
    }
    for (int i=1;i<=m;i++)
    {
        int x;
        scanf("%d",&x);
        Addedge(i+n,t1,n-x);
        Addedge(s,t1,x),Addedge(i+n,t,x);
    }
    for (int i=1;i<=k;i++)
    {
        int x,y;
        scanf("%d%d",&x,&y);
        cant[x][y]=1;
    }
    for (int i=1;i<=n;i++)
        for (int j=1;j<=m;j++)
            if (!cant[i][j])
                Addedge(i,n+j,1);
    int flow=dinic();
    if (flow==jud)
    {
        Addedge(t1,s1,inf);
        flow-=dinic();
        printf("%d\n",E[tot-1].flow);
    }
    else puts("JIONG!");
    return 0;
}

时间: 2024-08-28 07:07:43

【BZOJ 1458】 士兵占领的相关文章

bzoj 1458: 士兵占领 -- 最大流

1458: 士兵占领 Time Limit: 10 Sec  Memory Limit: 64 MB Description 有一个M * N的棋盘,有的格子是障碍.现在你要选择一些格子来放置一些士兵,一个格子里最多可以放置一个士兵,障碍格里不能放置士兵.我们称这些士兵占领了整个棋盘当满足第i行至少放置了Li个士兵, 第j列至少放置了Cj个士兵.现在你的任务是要求使用最少个数的士兵来占领整个棋盘. Input 第一行两个数M, N, K分别表示棋盘的行数,列数以及障碍的个数. 第二行有M个数表示

[bzoj 1458] 士兵占领(网络流dinic)

1458: 士兵占领 Time Limit: 10 Sec  Memory Limit: 64 MBSubmit: 784  Solved: 458[Submit][Status][Discuss] Description 有一个M * N的棋盘,有的格子是障碍.现在你要选择一些格子来放置一些士兵,一个格子里最多可以放置一个士兵,障碍格里不能放置士兵.我们称这些士兵占领了整个棋盘当满足第i行至少放置了Li个士兵, 第j列至少放置了Cj个士兵.现在你的任务是要求使用最少个数的士兵来占领整个棋盘.

[BZOJ 1458]士兵占领(网络流)

Description 有一个M * N的棋盘,有的格子是障碍.现在你要选择一些格子来放置一些士兵,一个格子里最多可以放置一个士兵,障碍格里不能放置士兵.我们称这些士兵占领了整个棋盘当满足第i行至少放置了Li个士兵, 第j列至少放置了Cj个士兵.现在你的任务是要求使用最少个数的士兵来占领整个棋盘. Solution 可以用上下界最小流来做,不过我觉得黄学长的这个思路也很直接 将每行每列都看成一个点,由s向行连边,容量为可以放置的士兵数-至少放置的士兵数 由列向t连边,容量为可以放置的士兵数-至少

BZOJ 1458 士兵占领

http://www.lydsy.com/JudgeOnline/problem.php?id=1458 题意:n x m的棋盘,k个位置不能放,每行和每列都有要求至少的士兵,求能否有最少的满足条件的士兵放法是多少. 思路:先全放满求能否满足,再尽量删掉士兵: 对于每行:能放m[i],至少放c[i],就从S连向i:m[i]-c[i],代表能删的最大 对于每列:能放m[i],至少放c[i],就从i+n连向T:m[i]-c[i],代表能删的最大 这样对于i,j这个位置如果可以放士兵,那就从i行连向j

BZOJ 1458 士兵占领 Dinic最大流

题目大意:给定一个m*n的棋盘,其中k个点有障碍,要求放置最少的士兵,使第i行有至少L[i]个,第j列有至少C[j]个 首先这种问题很明显的网络流 但是正图肯定是跑不了 限制条件是至少而且要求放置的也是最少 很难解决 反向考虑 将棋盘上先放满士兵 此时若不能满足条件则无解 然后求最多能撤掉多少个士兵 其中第i行最多撤去templ[i]-l[i]个士兵 templ[i]表示第i行当前放置的士兵个数 尼玛我的网络流是多久不写了--居然没连反向弧就跑样例--最逗的是数组开小一倍不报RE报WA-- #i

1458: 士兵占领

1458: 士兵占领 Time Limit: 10 Sec  Memory Limit: 64 MBSubmit: 1044  Solved: 598[Submit][Status][Discuss] Description 有一个M * N的棋盘,有的格子是障碍.现在你要选择一些格子来放置一些士兵,一个格子里最多可以放置一个士兵,障碍格里不能放置士兵.我们称这些士兵占领了整个棋盘当满足第i行至少放置了Li个士兵, 第j列至少放置了Cj个士兵.现在你的任务是要求使用最少个数的士兵来占领整个棋盘.

【BZOJ-1458】士兵占领 最大流

1458: 士兵占领 Time Limit: 10 Sec  Memory Limit: 64 MBSubmit: 782  Solved: 456[Submit][Status][Discuss] Description 有一个M * N的棋盘,有的格子是障碍.现在你要选择一些格子来放置一些士兵,一个格子里最多可以放置一个士兵,障碍格里不能放置士兵.我们称这些士兵占领了整个棋盘当满足第i行至少放置了Li个士兵, 第j列至少放置了Cj个士兵.现在你的任务是要求使用最少个数的士兵来占领整个棋盘.

bzoj1458: 士兵占领

逆向思维:最少多少士兵=最多放多少空格.于是跑最大流就OK了.取行列为节点. #include<cstdio> #include<cstring> #include<iostream> #include<cmath> #include<algorithm> using namespace std; #define rep(i,n) for(int i=1;i<=n;i++) #define clr(x,c) memset(x,c,sizeo

【bzoj1458】士兵占领

Description 有一个M * N的棋盘,有的格子是障碍.现在你要选择一些格子来放置一些士兵,一个格子里最多可以放置一个士兵,障碍格里不能放置士兵.我们称这些士兵占领了整个棋盘当满足第i行至少放置了Li个士兵, 第j列至少放置了Cj个士兵.现在你的任务是要求使用最少个数的士兵来占领整个棋盘. Input 第一行两个数M, N, K分别表示棋盘的行数,列数以及障碍的个数. 第二行有M个数表示Li. 第三行有N个数表示Ci. 接下来有K行,每行两个数X, Y表示(X, Y)这个格子是障碍. O