1. 程式人生 > >[UVALive] - 5817 Dhaka 2011 I - Truchet Tiling

[UVALive] - 5817 Dhaka 2011 I - Truchet Tiling

每塊磚可以拆成三個小塊,建圖處理每個塊的總面積和每個小塊的歸屬
查詢一個點的時候尋找一個最近的小塊進行查詢

#include<bits/stdc++.h>
using namespace std;
#define N 115
#define M 40000

const double pi=acos(-1);

char s[N][N];
int n,m,S[M],tot;
bool vis[M];

struct edge{int v,n;}e[M*10];
inline void Push(int u,int v)
{
    e[++tot]=(edge){v,S[u]};S[u]=tot;
}

inline int id(int x,int y,int c)
{
    return ((x-1)*m+y)*3-c+1;
}

struct node{int t,a,b;}f[M];

int gf(int a)
{
    return f[a].t==a?a:f[a].t=gf(f[a].t);
}

inline void merge(node &a,node &b)
{
    a.a+=b.a;
    a.b+=b.b;
    b.t=a.t;
}

inline void bfs(int st)
{
    queue<int> Q;
    Q.push(st);
    vis[st]=1;
    while (!Q.empty())
    {
        int h=Q.front();
        Q.pop();
        for (int i=S[h];i;i=e[i].n) 
        {
            if (!vis[e[i].v])
            {
                vis[e[i].v]=1;
                Q.push(e[i].v);
            }
            if (gf(h)!=gf(e[i].v)) merge(f[gf(h)],f[gf(e[i].v)]);
        }
    }
}

inline void prepare()
{
    int lim=id(n,m,1);
    memset(vis+1,0,lim*sizeof(bool));
    tot=0;
    memset(S+1,0,lim<<2);
    for (int i=1;i<=n;i++) for (int j=1;j<=m;j++)
    {
        if (i<n)
        {
            if (s[i][j]=='0')
            {
                if (s[i+1][j]=='0')
                {
                    Push(id(i,j,2),id(i+1,j,1));
                    Push(id(i,j,3),id(i+1,j,2));
                }
                else
                {
                    Push(id(i,j,2),id(i+1,j,2));
                    Push(id(i,j,3),id(i+1,j,3));
                }
            }
            else
            {
                if (s[i+1][j]=='0')
                {
                    Push(id(i,j,1),id(i+1,j,1));
                    Push(id(i,j,2),id(i+1,j,2));
                }
                else
                {
                    Push(id(i,j,1),id(i+1,j,2));
                    Push(id(i,j,2),id(i+1,j,3));
                }
            }
        }
        if (j<m)
        {
            if (s[i][j]=='0')
            {
                if (s[i][j+1]=='0')
                {
                    Push(id(i,j,2),id(i,j+1,1));
                    Push(id(i,j,3),id(i,j+1,2));
                }
                else
                {
                    Push(id(i,j,2),id(i,j+1,2));
                    Push(id(i,j,3),id(i,j+1,1));
                }
            }
            else
            {
                if (s[i][j+1]=='0')
                {
                    Push(id(i,j,3),id(i,j+1,1));
                    Push(id(i,j,2),id(i,j+1,2));
                }
                else
                {
                    Push(id(i,j,2),id(i,j+1,1));
                    Push(id(i,j,3),id(i,j+1,2));
                }
            }
        }
    }
    for (int i=1;i<=lim;i++)
    {
        int flag=(i%3==2)?1:0;
        f[i]=(node){i,flag,flag^1};
    }
    for (int i=1;i<=lim;i++) if (!vis[i]) bfs(i);
}

inline double get(int p)
{
    int tp=gf(p);
    return f[tp].a*(4-pi/2)+f[tp].b*(pi/4);
}

inline double find(int x,int y)
{
    int X=x/2+1,Y=y/2+1;
    if (((x&1)==0 && (y&1)!=0)||((y&1)==0 && (x&1)!=0)) return 0;
    if (X==n+1 && Y==m+1)
    {
        if (s[n][m]=='0') return get(id(n,m,3));
        return get(id(n,m,2));
    }
    if (X==n+1)
    {
        if (s[n][Y]=='0') return get(id(n,Y,2));
        return get(id(n,Y,1));
    }
    if (Y==m+1)
    {
        if (s[X][m]=='0') return get(id(X,m,2));
        return get(id(X,m,3));
    }
    if ((x&1) && (y&1)) return get(id(X,Y,2));
    if (s[X][Y]=='0') return get(id(X,Y,1));
    return get(id(X,Y,2));
}

inline void solve()
{
    scanf("%d%d",&n,&m);
    for (int i=1;i<=n;i++) scanf("%s",s[i]+1);
    prepare();
    int Q;
    scanf("%d",&Q);
    for (int x,y;Q--;)
    {
        scanf("%d%d",&x,&y);
        printf("%.4lf\n",find(x,y));
    }
}

int main()
{
    int T;
    scanf("%d",&T);
    for (int t=1;t<=T;t++) printf("Case %d:\n",t),solve();
}