1. 程式人生 > >【刷題】BZOJ 1458 士兵占領

【刷題】BZOJ 1458 士兵占領

template signed 所有 -- unsigned char 一個 turn 行數

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

Solution

這題是自己想了個麻煩一點,慢了一點的算法,但是思路特簡單
一行一列只能有一個,套路,行列連邊
超級源點向所有行連邊,流量為行上需要布滿的士兵,費用為 \(0\)
所有列向超級匯點連邊,流量為列上需要布滿的士兵,費用為 \(0\)
如果某個位置沒有障礙,那麽將它的行列連邊,流量為 \(1\) ,費用為 \(1\)
跑費用流
然後判斷源點連出的和流向匯點的邊是否滿流,滿了就是滿足行列限制了,否則無解

有解的話輸出費用

#include<bits/stdc++.h>
#define ui unsigned int
#define ll long long
#define db double
#define ld long double
#define ull unsigned long long
const int MAXN=200+10,MAXM=MAXN*MAXN+10,inf=0x3f3f3f3f;
int n,m,k,e=1,clk,s,t,answas,beg[MAXN],cur[MAXN],level[MAXN],p[MAXN],vis[MAXN],G[MAXN][MAXN],to[MAXM<<1],nex[MAXM<<1],cap[MAXM<<1],was[MAXM<<1],out[MAXM<<1];
std::queue<int> q;
template<typename T> inline void read(T &x)
{
    T data=0,w=1;
    char ch=0;
    while(ch!='-'&&(ch<'0'||ch>'9'))ch=getchar();
    if(ch=='-')w=-1,ch=getchar();
    while(ch>='0'&&ch<='9')data=((T)data<<3)+((T)data<<1)+(ch^'0'),ch=getchar();
    x=data*w;
}
template<typename T> inline void write(T x,char ch='\0')
{
    if(x<0)putchar('-'),x=-x;
    if(x>9)write(x/10);
    putchar(x%10+'0');
    if(ch!='\0')putchar(ch);
}
template<typename T> inline void chkmin(T &x,T y){x=(y<x?y:x);}
template<typename T> inline void chkmax(T &x,T y){x=(y>x?y:x);}
template<typename T> inline T min(T x,T y){return x<y?x:y;}
template<typename T> inline T max(T x,T y){return x>y?x:y;}
inline void insert(int x,int y,int z,int w)
{
    to[++e]=y;
    nex[e]=beg[x];
    out[e]=x;
    beg[x]=e;
    cap[e]=z;
    was[e]=w;
    to[++e]=x;
    nex[e]=beg[y];
    out[e]=y;
    beg[y]=e;
    cap[e]=0;
    was[e]=-w;
}
inline bool bfs()
{
    memset(level,inf,sizeof(level));
    level[s]=0;
    p[s]=1;
    q.push(s);
    while(!q.empty())
    {
        int x=q.front();
        q.pop();
        p[x]=0;
        for(register int i=beg[x];i;i=nex[i])
            if(cap[i]&&level[to[i]]>level[x]+was[i])
            {
                level[to[i]]=level[x]+was[i];
                if(!p[to[i]])p[to[i]]=1,q.push(to[i]);
            }
    }
    return level[t]!=inf;
}
inline int dfs(int x,int maxflow)
{
    if(x==t||!maxflow)return maxflow;
    vis[x]=clk;
    int res=0;
    for(register int &i=cur[x];i;i=nex[i])
        if((vis[x]^vis[to[i]])&&cap[i]&&level[to[i]]==level[x]+was[i])
        {
            int f=dfs(to[i],min(maxflow,cap[i]));
            res+=f;
            cap[i]-=f;
            cap[i^1]+=f;
            answas+=f*was[i];
            maxflow-=f;
            if(!maxflow)break;
        }
    return res;
}
inline void MCMF()
{
    while(bfs())clk++,memcpy(cur,beg,sizeof(cur)),dfs(s,inf);
}
int main()
{
    read(n);read(m);read(k);
    s=n+m+1,t=s+1;
    for(register int i=1,x;i<=n;++i)read(x),insert(s,i,x,0);
    for(register int i=1,x;i<=m;++i)read(x),insert(i+n,t,x,0);
    while(k--)
    {
        int x,y;read(x);read(y);
        G[x][y]=1;
    }
    for(register int i=1;i<=n;++i)
        for(register int j=1;j<=m;++j)
            if(!G[i][j])insert(i,j+n,1,1);
    MCMF();
    for(register int i=2;i<=e;i+=2)
        if((out[i]==s||to[i]==t)&&cap[i])
        {
            puts("JIONG");
            return 0;
        }
    write(answas,'\n');
    return 0;
}

【刷題】BZOJ 1458 士兵占領