BZOJ 1458 士兵占领 Dinic最大流

题目大意:给定一个m*n的棋盘,其中k个点有障碍,要求放置最少的士兵,使第i行有至少L[i]个,第j列有至少C[j]个

首先这种问题很明显的网络流 但是正图肯定是跑不了 限制条件是至少而且要求放置的也是最少 很难解决

反向考虑 将棋盘上先放满士兵 此时若不能满足条件则无解 然后求最多能撤掉多少个士兵 其中第i行最多撤去templ[i]-l[i]个士兵 templ[i]表示第i行当前放置的士兵个数

尼玛我的网络流是多久不写了……居然没连反向弧就跑样例……最逗的是数组开小一倍不报RE报WA……

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define M 110
#define s 0
#define t (m+n+1)
#define INF 0x3f3f3f3f
using namespace std;
struct abcd{
    int to,f,next;
}table[M*M<<1];
int head[M+M],tot=1;
int m,n,k,ans;
int l[M],c[M];
int templ[M],tempc[M];
bool ban[M][M];
int d[M+M];
void Add(int x,int y,int z)
{
    table[++tot].to=y;
    table[tot].f=z;
    table[tot].next=head[x];
    head[x]=tot;
}
bool BFS()
{
    int i;
    static int q[65540];
    static unsigned short r,h;
    r=h=0;
    memset(d,-1,sizeof d);
    d[s]=0;q[++r]=s;
    while(r!=h)
    {
        int x=q[++h];
        for(i=head[x];i;i=table[i].next)
            if(table[i].f)
            {
                if(~d[table[i].to])
                    continue;
                d[table[i].to]=d[x]+1;
                q[++r]=table[i].to;
                if(table[i].to==t)
                    return true;
            }
    }
    return false;
}
int Dinic(int x,int flow)
{
    int i,left=flow;
    if(x==t)
        return flow;
    for(i=head[x];i&&left;i=table[i].next)
        if(table[i].f&&d[table[i].to]==d[x]+1)
        {
            int temp=Dinic(table[i].to,min(left,table[i].f));
            if(!temp) d[table[i].to]=-1;
            left-=temp;
            table[i].f-=temp;
            table[i^1].f+=temp;
        }
    return flow-left;
}
int main()
{
    int i,j,x,y;
    cin>>m>>n>>k;
    for(i=1;i<=m;i++)
        scanf("%d",&l[i]),templ[i]=n;
    for(i=1;i<=n;i++)
        scanf("%d",&c[i]),tempc[i]=m;
    for(i=1;i<=k;i++)
    {
        scanf("%d%d",&x,&y);
        if(--templ[x]<l[x])
        {
            puts("JIONG!");
            return 0;
        }
        if(--tempc[y]<c[y])
        {
            puts("JIONG!");
            return 0;
        }
        ban[x][y]=true;
    }
    ans=m*n-k;
    for(i=1;i<=m;i++)
        for(j=1;j<=n;j++)
            if(!ban[i][j])
                Add(i,m+j,1),Add(m+j,i,0);
    for(i=1;i<=m;i++)
        Add(s,i,templ[i]-l[i]),Add(i,s,0);
    for(i=1;i<=n;i++)
        Add(m+i,t,tempc[i]-c[i]),Add(t,m+i,0);
    while( BFS() )
        ans-=Dinic(s,INF);
    cout<<ans<<endl;
}
时间: 2024-09-30 16:38:08

BZOJ 1458 士兵占领 Dinic最大流的相关文章

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

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 MB Submit: 632 Solved: 366 [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

P4311 士兵占领[最大流]

题目地址 有一个$M * N$的棋盘,有的格子是障碍.现在你要选择一些格子来放置一些士兵,一个格子里最多可以放置一个士兵,障碍格里不能放置士兵.我们称这些士兵占领了整个棋盘当满足第i行至少放置了$L_i$个士兵, 第j列至少放置了$C_j$个士兵.现在你的任务是要求使用最少个数的士兵来占领整个棋盘. 考虑到说棋盘问题,选的行和列之间是有关联的,彼此制约着数量,就应该可以从网络流入手(然而如果我不是奔网络流刷题来的说不定会瞎写一发dp) 最小化答案,应该对应的是最大流的反向转化(也就是化加为减,求