zoukankan      html  css  js  c++  java
  • bzoj1412

    1412: [ZJOI2009]狼和羊的故事

    Time Limit: 10 Sec  Memory Limit: 162 MB
    Submit: 3443  Solved: 1725
    [Submit][Status][Discuss]

    Description

    “狼爱上羊啊爱的疯狂,谁让他们真爱了一场;狼爱上羊啊并不荒唐,他们说有爱就有方向......” Orez听到这首歌,心想:狼和羊如此和谐,为什么不尝试羊狼合养呢?说干就干! Orez的羊狼圈可以看作一个n*m个矩阵格子,这个矩阵的边缘已经装上了篱笆。可是Drake很快发现狼再怎么也是狼,它们总是对羊垂涎三尺,那首歌只不过是一个动人的传说而已。所以Orez决定在羊狼圈中再加入一些篱笆,还是要将羊狼分开来养。 通过仔细观察,Orez发现狼和羊都有属于自己领地,若狼和羊们不能呆在自己的领地,那它们就会变得非常暴躁,不利于他们的成长。 Orez想要添加篱笆的尽可能的短。当然这个篱笆首先得保证不能改变狼羊的所属领地,再就是篱笆必须修筑完整,也就是说必须修建在单位格子的边界上并且不能只修建一部分。

    Input

    文件的第一行包含两个整数n和m。接下来n行每行m个整数,1表示该格子属于狼的领地,2表示属于羊的领地,0表示该格子不是任何一只动物的领地。

    Output

    文件中仅包含一个整数ans,代表篱笆的最短长度。

    Sample Input

    2 2
    2 2
    1 1

    Sample Output

    2

    数据范围
    10%的数据 n,m≤3
    30%的数据 n,m≤20
    100%的数据 n,m≤100
     

    很裸的最小割模型了。把狼和羊分开即可。

      S向狼连容量无穷边,羊向T连容量无穷边。

      狼向周围空地和羊连容量1的边,空地向周围空地和羊连容量1边。

      最小割后,和S连的点即表示狼的领地,与T相连的点表示羊的领地。

    #include<cstdio>
    #include<iostream>
    #include<algorithm>
    #include<cstring>
    #include<queue>
    #define ll long long
    #define inf 0x3f3f3f3f
    #define N 105
    using namespace std;
    int n,m,S,T,tot,mp[N][N],hd[N*N],cur[N*N],d[N*N],vis[N*N];
    int dx[]={0,0,1,-1};int dy[]={1,-1,0,0};
    struct edge{int v,cap,next;}e[N*N*8];
    int get(int i,int j){return (i-1)*m+j;}
    bool check(int i,int j){return i>=1&&i<=n&&j>=1&&j<=m;}
    void adde(int u,int v,int c){
        e[tot].v=v;
        e[tot].next=hd[u];
        e[tot].cap=c;
        hd[u]=tot++;
    }
    bool bfs(){
        queue<int>q;
        memset(vis,0,sizeof(vis));
        d[S]=0;q.push(S);vis[S]=1;
        while(!q.empty()){
            int u=q.front();q.pop();
            for(int i=hd[u];~i;i=e[i].next){
                int v=e[i].v;
                if(e[i].cap<=0||vis[v])continue;
                d[v]=d[u]+1;vis[v]=1;q.push(v);
            }
        }
        return vis[T];
    }
    int dfs(int u,int a){
        if(u==T||!a)return a;
        int fl=0,f;
        for(int &i=cur[u];~i;i=e[i].next){
            if(e[i].cap<=0)continue;
            int v=e[i].v;
            if(d[v]==d[u]+1&&(f=dfs(v,min(a,e[i].cap)))){
                fl+=f;a-=f;e[i].cap-=f;
                e[i^1].cap+=f;if(!a)break;
            }
        }
        return fl;
    }
    int main(){
    #ifdef wsy
        freopen("data.in","r",stdin);
    #else
        //freopen(".in","r",stdin);
        //freopen(".out","w",stdout);
    #endif
        scanf("%d%d",&n,&m);
        memset(hd,-1,sizeof(hd));
        S=0;T=n*m+1;
        for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++){
            scanf("%d",&mp[i][j]);
            if(mp[i][j]==1)adde(S,get(i,j),inf),adde(get(i,j),S,0);
            else if(mp[i][j]==2)adde(get(i,j),T,inf),adde(T,get(i,j),0);
        }
        for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++){
            if(mp[i][j]==2)continue;
            int idx=get(i,j);
            for(int k=0;k<4;k++){
                int nx=i+dx[k],ny=j+dy[k];
                if(!check(nx,ny))continue;
                int nid=get(nx,ny);
                if(mp[i][j]==1){
                    if(mp[nx][ny]!=1)adde(idx,nid,1),adde(nid,idx,0);
                }
                else if(mp[nx][ny]!=1)adde(idx,nid,1),adde(nid,idx,0);
            }
        }
        int ans=0;
        while(bfs()){
            for(int i=S;i<=T;i++)cur[i]=hd[i];
            ans+=dfs(S,0x3f3f3f3f);
        }
        printf("%d",ans);
        return 0;
    }
    

      

  • 相关阅读:
    android中src和background区别
    html标签大全
    android横竖屏切换时activity的生命周期
    onInterceptTouchEvent和onTouchEvent调用时序
    Android Activity单例
    Android dispatchTouchEvent
    android 2D API相关
    杭电 1085 Holding BinLaden Captive!
    杭电 1715 大菲波数
    杭电 1492 The number of divisors(约数) about Humble Numbers
  • 原文地址:https://www.cnblogs.com/wsy01/p/7932157.html
Copyright © 2011-2022 走看看