zoukankan      html  css  js  c++  java
  • BZOJ 1412: [ZJOI2009]狼和羊的故事

    BZOJ 1412: [ZJOI2009]狼和羊的故事

    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

    HINT

    Source

    Solution

    问题实际转化成了两个点集的分割问题,即最小割。
    先让S连向所有羊,T连向所有狼,容量都为inf。(保证不会被割掉)
    再让所有狼连向四联通块,空地也是。跑最大流即可。

    Code

    #include<cstdio>
    #include<cstring>
    #include<cmath>
    #include<queue>
    #include<algorithm>
    #define fo(i,a,b) for(int i=a;i<=b;i++)
    #define fd(i,a,b) for(int i=a;i>=b;i--)
    #define rep(i,x) for(int i=head[x];i;i=e[i].next)
    #define mem(a,x) memset(a,x,sizeof(a))
    typedef long long LL;
    typedef double DB;
    using namespace std;
    template <typename T> inline T read(T &a) {
        T x=0,f=1;char ch=getchar();
        while(ch<'0'||ch>'9') f=(ch=='-')?-1:f,ch=getchar();
        while(ch>='0'&&ch<='9') x=x*10+(ch-'0'),ch=getchar();a=f*x;
    }
    const int inf=0x3f3f3f3f,T=1e4+1;
    int head[10005],q[10005],h[10005],cur[10005];
    int cnt=1,ans,n,m;
    int xx[4]= {0,0,1,-1},yy[4]= {1,-1,0,0},mp[105][105];
    struct data {int to,next,v;} e[500001];
    void ins(int u,int v,int w) {e[++cnt]=(data){v,head[u],w},head[u]=cnt;}
    void insert(int u,int v,int w) {ins(u,v,w),ins(v,u,0);}
    bool bfs() {
    	int t=0,w=1,i,now;
    	memset(h,-1,sizeof(h));
    	q[0]=0,h[0]=0;
    	while(t<w) {
    		now=q[t++];
    		rep(i,now) if(e[i].v&&h[e[i].to]==-1) h[e[i].to]=h[now]+1,q[w++]=e[i].to;
    	}
    	return !(h[T]==-1);
    }
    int dfs(int x,int f) {
    	if(x==T) return f;
    	int w,used=0;
    	for(int &i=cur[x];i;i=e[i].next) 
    		if(e[i].v&&h[e[i].to]==h[x]+1) {
    			w=f-used;
    			w=dfs(e[i].to,min(w,e[i].v));
    			e[i].v-=w,e[i^1].v+=w;
    			used+=w;
    			if(used==f) return f;
    		}
    	if(!used) h[x]=-1;
    	return used;
    }
    void dinic() {
    	while(bfs()) {
    		fo(i,0,T) cur[i]=head[i];
    		ans=ans+dfs(0,inf);
    	}
    }
    void build() {
    	fo(i,1,n) fo(j,1,m) {
    		if(mp[i][j]==1) insert(0,(i-1)*m+j,inf);
    		if(mp[i][j]==2) insert((i-1)*m+j,T,inf);
    		fo(k,0,3) {
    			int x=i+xx[k],y=j+yy[k];
    			if(x<1||x>n||y<1||y>m||mp[i][j]==2) continue;
    			if(mp[i][j]!=1||mp[x][y]!=1) insert((i-1)*m+j,(x-1)*m+y,1);
    		}
    	}
    }
    int main() {
    	freopen("1412.in","r",stdin);
    	read(n),read(m);
    	fo(i,1,n) fo(j,1,m) read(mp[i][j]);
    	build(),dinic();
    	printf("%d",ans);
    	return 0;
    }
    
  • 相关阅读:
    绝对干货:供个人开发者赚钱免费使用的一些好的API接口
    科普技术贴:个人开发者的那些赚钱方式
    北漂程序员的笑与泪
    非著名程序员公众号
    北漂程序员的笑与泪
    【有人@我】Android中高亮变色显示文本中的关键字
    新时代的coder如何成为专业程序员
    自定义圆形控件RoundImageView并认识一下attr.xml
    偷天换日:网络劫持,网页js被伪装替换。
    jeesite 去掉 /a
  • 原文地址:https://www.cnblogs.com/patricksu/p/8081174.html
Copyright © 2011-2022 走看看