JZOJ4016. 【雅礼联考DAY01】圈地为王

Description

在 n 行 m 列的网格中,你要圈一些地。
你从左上角出发,最后返回左上角,路径内部的区域视为被你圈住。 你不可以进入网格内部, 只能在边上行走。 你的路径不能在左上角以外自交, 但是边足够宽, 你可以重复经过而不自交。
网格中有一些格子对你很重要,你要尽量圈住它;而另一些格子对你有坏处,你不能圈住它。
求圈住 i 个重要的格子的最小路径长度。

Input

n 行,每行 m 个字符。
‘I’表示重要的格子, ‘X’表示有坏处的格子, ‘.’表示其他格子。

Output

输出重要的格子数行, 第 i 行表示圈住 i 个重要的格子的最小路径长度。

Sample Input

X.I
.I.
I..

Sample Output

8
10
14
这里写图片描述

题解

首先我们需要知道如何判断一个点是否在一个多边形里面,
这个很简单:从这个点引出一条射线,看看它与多边形的边有多少个交点,
如果是奇数个,就在多边形里面,偶数个就不在。

关于自交的问题,就将它当作没有自交就好了。

看到数据范围,特殊点只有很少,考虑如何设状态,
f x , y , s 表示当前走的点(x,y),特殊格子上面经过的线的奇偶性的2进制状态,
有了这个状态就可以bfs了。

code

#include <queue>
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <string.h>
#include <cmath>
#include <math.h>
#include <time.h>
#define ll long long
#define N 2560000
#define M 103
#define db double
#define P putchar
#define G getchar
#define inf 998244353
#define pi 3.1415926535897932384626433832795
using namespace std;
char ch;
void read(int &n)
{
    n=0;
    ch=G();
    while((ch<'0' || ch>'9') && ch!='-')ch=G();
    ll w=1;
    if(ch=='-')w=-1,ch=G();
    while('0'<=ch && ch<='9')n=(n<<3)+(n<<1)+ch-'0',ch=G();
    n*=w;
}

int max(int a,int b){return a>b?a:b;}
int min(int a,int b){return a<b?a:b;}
ll abs(ll x){return x<0?-x:x;}
ll sqr(ll x){return x*x;}
void write(ll x){if(x>9) write(x/10);P(x%10+'0');}

int f[53][53][1030],n,m,x,y,xx,yy,t,v,ss;
int z[13],fx[4][2]={{-1,0},{0,-1},{1,0},{0,1}};
int head,tail,q[3][N*8],ans[13],p[2][13],cnt;
bool bz[53][53][1030];
char s[53][53];

int get(int x,int y,int s)
{
    for(int i=1;i<=cnt;i++)
        if(p[1][i]==y && p[0][i]>x)s^=z[i-1];
    return s;
}

void dfs(int ss,int x,int y)
{
    ans[y]=min(ans[y],f[0][0][ss]);
    if(x>cnt)return;
    if(s[p[0][x]][p[1][x]]=='I')dfs(ss|z[x-1],x+1,y+1);
    dfs(ss,x+1,y);
}

int main()
{   
    z[0]=1;
    for(int i=1;i<12;i++)
        z[i]=z[i-1]<<1;

    for(n=1;scanf("%c",&ch)!=EOF;n++)
    {
        for(m=0;ch=='X' || ch=='I' || ch=='.';ch=G())
        {
            s[n][++m]=ch;
            if(ch!='.')cnt++,p[0][cnt]=n,p[1][cnt]=m;
        } 
    }

    memset(f,127,sizeof(f));
    memset(bz,1,sizeof(bz));
    f[0][0][0]=0;bz[0][0][0]=0;n--;
    for(head=0,tail=1;head<tail;)
    {
        head++;
        x=q[0][head];
        y=q[1][head];
        t=q[2][head];
        v=f[x][y][t];

        for(int k=0;k<4;k++)
        {
            xx=x+fx[k][0];
            yy=y+fx[k][1];
            ss=t;
            if(xx<0 || yy<0 || xx>n || yy>m)continue;
            if(k==1)ss=get(x,y,ss);
            if(k==3)ss=get(x,yy,ss);

            if(f[xx][yy][ss]>v+1)
            {
                f[xx][yy][ss]=v+1;
                if(bz[xx][yy][ss])
                {
                    bz[xx][yy][ss]=0;
                    tail++;
                    q[0][tail]=xx;
                    q[1][tail]=yy;
                    q[2][tail]=ss;
                }
            }
        }
        bz[x][y][t]=1;
    }

    memset(ans,127,sizeof(ans));
    dfs(0,1,0);
    for(int i=1;i<=cnt;i++)
        if(ans[i]<1000000)write(ans[i]),P('\n');

    return 0;
}

猜你喜欢

转载自blog.csdn.net/lijf2001/article/details/81051820