zoukankan      html  css  js  c++  java
  • 【BZOJ4808/3175】马/[Tjoi2013]攻击装置 最小割

    【BZOJ4808】马

    Description

    众所周知,马后炮是中国象棋中很厉害的一招必杀技。"马走日字"。本来,如果在要去的方向有别的棋子挡住(俗称"蹩马腿"),则不允许走过去。为了简化问题,我们不考虑这一点。马跟马显然不能在一起打起来,于是rly在一天再次借来了许多许多的马在棋盘上摆了起来……但这次,他实在没兴趣算方案数了,所以他只想知道在N×M的矩形方格中摆马使其互不吃到的情况下的最多个数。但是,有一个很不幸的消息,rly由于玩得太Happy,质量本来就不好的棋盘被rly弄坏了,不过幸好只是破了其中的一些格子(即不能再放子了),问题还是可以继续解决的。

    Input

    一行,两个正整数N和M。
    接下来N行,每行M个数,要么为0,表示没坏,要么为1,表示坏了。
    N<=200,M<=200

    Output

    一行,输出最多的个数。

    Sample Input

    2 3
    0 1 0
    0 1 0

    Sample Output

    2

    题解:黑白染色,然后无脑最小割~

    #include <cstdio>
    #include <cstring>
    #include <iostream>
    #include <queue>
    #define num(A,B) ((A)*m-m+B)
    #define ok(A,B)	(A>=1&&A<=n&&B>=1&&B<=m&&!map[A][B])
    using namespace std;
    int n,m,cnt,tot,ans;
    int dx[]={-1,-1,1,1,-2,-2,2,2},dy[]={2,-2,2,-2,1,-1,1,-1};
    int d[40010],next[500010],val[500010],head[40010],to[500010],map[210][210];
    queue<int> q;
    void add(int a,int b,int c)
    {
    	to[cnt]=b,val[cnt]=c,next[cnt]=head[a],head[a]=cnt++;
    	to[cnt]=a,val[cnt]=0,next[cnt]=head[b],head[b]=cnt++;
    }
    int dfs(int x,int mf)
    {
    	if(x==n*m+1)	return mf;
    	int i,k,temp=mf;
    	for(i=head[x];i!=-1;i=next[i])
    	{
    		if(d[to[i]]==d[x]+1&&val[i])
    		{
    			k=dfs(to[i],min(mf,val[i]));
    			if(!k)	d[to[i]]=0;
    			val[i]-=k,val[i^1]+=k,temp-=k;
    			if(!temp)	break;
    		}
    	}
    	return mf-temp;
    }
    int bfs()
    {
    	memset(d,0,sizeof(d));
    	while(!q.empty())	q.pop();
    	int i,u;
    	d[0]=1,q.push(0);
    	while(!q.empty())
    	{
    		u=q.front(),q.pop();
    		for(i=head[u];i!=-1;i=next[i])
    		{
    			if(val[i]&&!d[to[i]])
    			{
    				d[to[i]]=d[u]+1;
    				if(to[i]==n*m+1)	return 1;
    				q.push(to[i]);
    			}
    		}
    	}
    	return 0;
    }
    int main()
    {
    	scanf("%d%d",&n,&m);
    	int i,j,k,a;
    	memset(head,-1,sizeof(head));
    	for(i=1;i<=n;i++)	for(j=1;j<=m;j++)	scanf("%d",&map[i][j]);
    	for(i=1;i<=n;i++)
    	{
    		for(j=1;j<=m;j++)
    		{
    			if(map[i][j])	continue;
    			tot++;
    			if((i^j)&1)
    			{
    				add(0,num(i,j),1);
    				for(k=0;k<8;k++)	if(ok(i+dx[k],j+dy[k]))	add(num(i,j),num(i+dx[k],j+dy[k]),1<<30);
    			}
    			else	add(num(i,j),n*m+1,1);
    		}
    	}
    	while(bfs())	ans+=dfs(0,1<<30);
    	printf("%d",tot-ans);
    	return 0;
    }

    【BZOJ3175】[Tjoi2013]攻击装置

    题解:同上题

    #include <cstdio>
    #include <cstring>
    #include <iostream>
    #include <queue>
    #define num(A,B) ((A-1)*n+B)
    #define ok(A,B) (A>=1&&A<=n&&B>=1&&B<=n&&str[A][B-1]=='0')
    using namespace std;
    int n,cnt,tot,ans,S,T;
    int dx[]={-1,-1,1,1,-2,-2,2,2},dy[]={2,-2,2,-2,1,-1,1,-1};
    int d[40010],next[500010],val[500010],head[40010],to[500010];
    char str[210][210];
    queue<int> q;
    void add(int a,int b,int c)
    {
        to[cnt]=b,val[cnt]=c,next[cnt]=head[a],head[a]=cnt++;
        to[cnt]=a,val[cnt]=0,next[cnt]=head[b],head[b]=cnt++;
    }
    int dfs(int x,int mf)
    {
        if(x==T)    return mf;
        int i,k,temp=mf;
        for(i=head[x];i!=-1;i=next[i])
        {
            if(d[to[i]]==d[x]+1&&val[i])
            {
                k=dfs(to[i],min(mf,val[i]));
                if(!k)  d[to[i]]=0;
                val[i]-=k,val[i^1]+=k,temp-=k;
                if(!temp)   break;
            }
        }
        return mf-temp;
    }
    int bfs()
    {
        memset(d,0,sizeof(d));
        while(!q.empty())   q.pop();
        int i,u;
        d[S]=1,q.push(S);
        while(!q.empty())
        {
            u=q.front(),q.pop();
            for(i=head[u];i!=-1;i=next[i])
            {
                if(val[i]&&!d[to[i]])
                {
                    d[to[i]]=d[u]+1;
                    if(to[i]==T)    return 1;
                    q.push(to[i]);
                }
            }
        }
        return 0;
    }
    int main()
    {
        scanf("%d",&n);
        int i,j,k;
        S=0,T=n*n+1;
        memset(head,-1,sizeof(head));
        for(i=1;i<=n;i++)	scanf("%s",str[i]);
        for(i=1;i<=n;i++)
        {
            for(j=1;j<=n;j++)
            {
                if(str[i][j-1]=='1')   continue;
                tot++;
                if((i^j)&1)
                {
                    add(S,num(i,j),1);
                    for(k=0;k<8;k++) if(ok(i+dx[k],j+dy[k])) add(num(i,j),num(i+dx[k],j+dy[k]),1<<30);
                }
                else    add(num(i,j),T,1);
            }
        }
        while(bfs())    ans+=dfs(0,1<<30);
        printf("%d",tot-ans);
        return 0;
    }
  • 相关阅读:
    Step by step Dynamics CRM 2013安装
    SQL Server 2012 Managed Service Account
    Step by step SQL Server 2012的安装
    Step by step 活动目录中添加一个子域
    Step by step 如何创建一个新森林
    向活动目录中添加一个子域
    活动目录的信任关系
    RAID 概述
    DNS 正向查找与反向查找
    Microsoft Dynamics CRM 2013 and 2011 Update Rollups and Service Packs
  • 原文地址:https://www.cnblogs.com/CQzhangyu/p/6658180.html
Copyright © 2011-2022 走看看