码迷,mamicode.com
首页 > 其他好文 > 详细

【GMOJ4016】圈地为王

时间:2020-02-08 17:39:51      阅读:65      评论:0      收藏:0      [点我收藏+]

标签:href   长度   clu   ++   while   queue   https   pop   偶数   

题目

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

思路

这道题挺妙的。
考虑如果一个格子正上方的边经过了奇数次,那么这个点最终就被围住了,如果它上方的点经过了偶数次,那么就没有被围住。
由于特殊点(重要点+坏点)只有\(10\)个。考虑状压。
\(f[i][j][S]\)表示现在走到点\((i,j)\),每一个重要点的上方经过的次数的奇偶性为\(S\)的最少步数。
那么可以\(bfs\)转移,注意维护\(S\)即可。
时间复杂度\(O(2^knm)\),其中\(k\)表示特殊点的个数。

代码

#include <queue>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;

const int N=55,MAXN=1025,Inf=1e9;
const int dx[]={0,0,0,-1,1},dy[]={0,-1,1,0,0};
int n,m,cnt,Sbad,f[N][N][MAXN],S[N][N],id[N][N],ans[N];
char a[N][N];
queue<int> qx,qy,qs;

void bfs()
{
    memset(f,0x3f3f3f3f,sizeof(f));
    f[1][1][0]=0;
    qx.push(1); qy.push(1); qs.push(0);
    while (qx.size())
    {
        int x=qx.front(),y=qy.front(),s=qs.front();
        qx.pop(); qy.pop(); qs.pop();
        for (int i=1;i<=4;i++)
        {
            int xx=x+dx[i],yy=y+dy[i],ss;
            if (yy!=y) ss=s^S[x][min(y,yy)];
                else ss=s;
            if (xx<1 || yy<1 || xx>n || yy>m || f[xx][yy][ss]<Inf) continue;
            f[xx][yy][ss]=f[x][y][s]+1;
            qx.push(xx); qy.push(yy); qs.push(ss);
        }
    }
}

int main()
{
    for (int i=1;scanf("%s",a[i]+1)>0;i++) n++;
    m=strlen(a[1]+1)+1; n++;
    for (int i=1;i<n;i++)
        for (int j=1;j<m;j++)
            if (a[i][j]!='.')
            {
                id[i][j]=++cnt;
                if (a[i][j]=='X') Sbad|=(1<<id[i][j]-1);
                for (int k=1;k<=i;k++)
                    S[k][j]|=(1<<id[i][j]-1);
            }
    bfs();
    memset(ans,0x3f3f3f3f,sizeof(ans));
    for (int i=1;i<(1<<cnt);i++)
        if (!(i&Sbad))
        {
            int s=0;
            for (int j=i;j;j>>=1) s+=(j&1);
            ans[s]=min(ans[s],f[1][1][i]);
        }
    for (int i=1;ans[i]<Inf;i++)
        printf("%d\n",ans[i]);
    return 0;
}

【GMOJ4016】圈地为王

标签:href   长度   clu   ++   while   queue   https   pop   偶数   

原文地址:https://www.cnblogs.com/stoorz/p/12283859.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!