[USACO17FEB]Why Did the Cow Cross the Road III S题解

题目链接
洛谷P3663
bzoj4997

思路
这道题要我们求遥远的牛,其实就是把道路当成障碍,去统计每个连通块有多少头牛,不在一个连通块的牛都是遥远的,可以用乘法原理直接计算。

在找连通块时用bfs搜索,暴力统计连通块。存图时可以用三维数组存它能否走到相邻的格子,但我用的是二维数组进行二进制压缩,可以省空间,也好看一些。

具体还有一些细节和优化,代码里有注释。

code:

#include<cstdio>
int c[110][110],q[210][2];//c存能否走到相邻的格子,q是循环队列
bool f[110][110],b[110][110];//f为有无牛,b标记是否被扩张过
const int dx[4]={0,1,0,-1},dy[4]={1,0,-1,0};\\东南西北
int bfs(int ii,int jj)//寻找连通块
{
    int q1=0,q2=1,sum=0;
    b[ii][jj]=1;
    q[0][0]=ii;
    q[0][1]=jj;
    while(q1!=q2)
    {
        int x=q[q1][0],y=q[q1][1];
        if(++q1==210)q1=0;//循环
        sum+=f[x][y];
        for(int i=0;i<=3;i++)
        {
            int xx=x+dx[i],yy=y+dy[i];
            if(!(c[x][y]&1<<i/*二进制压缩*/)&&!b[xx][yy])
            {
                b[xx][yy]=1;
                q[q2][0]=xx;
                q[q2][1]=yy;
                if(++q2==210)q2=0;//循环
            }
        }
    }
    return sum;
}
int main()
{
    int n,k,r,x1,x2,y1,y2,ans=0;
    scanf("%d%d%d",&n,&k,&r);
    for(int i=1;i<=n;i++)
    {
    	//边界
        c[i][1]|=4;
        c[i][n]|=1;
        c[1][i]|=8;
        c[n][i]|=2;
    }
    for(int i=1;i<=r;i++)
    {
        scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
        for(int i=0;i<=3;i++)
            if(dx[i]+x1==x2&&dy[i]+y1==y2)
            {
                c[x1][y1]|=1<<i;//道路
                c[x2][y2]|=1<<(i+2&3);
            }
    }
    for(int i=1;i<=k;i++)
    {
        scanf("%d%d",&x1,&y1);
        f[x1][y1]=1;//牛的位置
    }
    for(int i=1;i<=n;i++)
        for(int j=1;j<=n;j++)
            if(!b[i][j])//如果当前连通块未被扩张,就扩张
            {
                int t=bfs(i,j);
                ans+=t*(k-t);//统计与当前连通块遥远的牛
            }
    printf("%d\n",ans>>1);//每头牛自己计算一次,被其他牛计算一次,所以除以二
}
posted @ 2019-08-19 17:04  胡昊天  阅读(195)  评论(0编辑  收藏  举报