codeforces 596E Wilbur and Strings(DFS)

题目链接

E. Wilbur and Strings
time limit per test
3 seconds
memory limit per test
256 megabytes
input
standard input
output
standard output

Wilbur the pig now wants to play with strings. He has found an n by m table consisting only of the digits from 0 to 9 where the rows are numbered 1 to n and the columns are numbered 1 to m. Wilbur starts at some square and makes certain moves. If he is at square (x, y) and the digit d (0 ≤ d ≤ 9) is written at position (x, y), then he must move to the square (x + ad, y + bd), if that square lies within the table, and he stays in the square (x, y) otherwise. Before Wilbur makes a move, he can choose whether or not to write the digit written in this square on the white board. All digits written on the whiteboard form some string. Every time a new digit is written, it goes to the end of the current string.

Wilbur has q strings that he is worried about. For each string si, Wilbur wants to know whether there exists a starting position (x, y) so that by making finitely many moves, Wilbur can end up with the string si written on the white board.

Input

The first line of the input consists of three integers n, m, and q (1 ≤ n, m, q ≤ 200) — the dimensions of the table and the number of strings to process, respectively.

Each of the next n lines contains m digits from 0 and 9 giving the table itself.

Then follow 10 lines. The i-th of them contains the values ai - 1 and bi - 1 ( - 200 ≤ ai, bi ≤ 200), i.e. the vector that Wilbur uses to make a move from the square with a digit i - 1 in it.

There are q lines that follow. The i-th of them will contain a string si consisting only of digits from 0 to 9. It is guaranteed that the total length of these q strings won't exceed 1 000 000.

Output

For each of the q strings, print "YES" if Wilbur can choose x and y in order to finish with this string after some finite number of moves. If it's impossible, than print "NO" for the corresponding string.

Sample test(s)
Input
1 1 2
0
1 1
1 1
1 1
1 1
1 1
1 1
1 1
1 1
1 1
1 1
0000000000000
2413423432432
Output
YES
NO
Input
4 2 5
01
23
45
67
0 1
0 -1
0 1
0 -1
0 1
0 -1
0 1
0 -1
0 1
0 -1
0000000000
010101011101
32232232322
44343222342444324
6767
Output
YES
YES
YES
NO
YES
Note

In the first sample, there is a 1 by 1 table consisting of the only digit 0. The only move that can be made is staying on the square. The first string can be written on the white board by writing 0 repeatedly. The second string cannot be written as there is no 2 on the table.

题意:n*m的矩阵,每个格子内有一个(0-9)的数字。若当前在格子(i,j)那么下一步必须前往格子(i+a[i],j+b[j])(当且仅当该格子在矩阵内,否则任然在原地)。到了一个格子可以选择盖格子上的数字并将它加入已选数字的末尾,也可以不选。有q次询问,每次询问一个字符串,求解任选起点,在有限的步数内能否获得该字符串。

题解:根据题意建图。有一个特点,每一个格子出度最大为1。那么以任意一个点为起点一直走,那么路径一定唯一,末尾要么是个点,要么是个环。我们把环缩点,再反向建图,每次询问的一个字符串的时候,从入度为0的点开始,DFS遍历图,能匹配则匹配,贪心求解即可。由于图是个DAG,每个点的入度最大为1,那么每次询问,每个点最多只访问一次。复杂度O(q*n*m)

代码如下:

#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<string>
#include<string.h>
#include<math.h>
#include<vector>
#include<queue>
#include<stack>
#include<map>
#include<set>
#include<list>
typedef __int64 LL;
typedef unsigned __int64 LLU;
const int nn=210;
const int inf=0x3fffffff;
const LL inf64=(LL)inf*inf;
using namespace std;
int n,m,q;
char stu[nn][nn];
int sz[nn*nn];
int tu[nn][nn];
int a[nn],b[nn];
char s[nn*10000];
struct node
{
    int en,next;
}E[nn*nn];
int p[nn*nn],num;
int rd[nn*nn];
void init()
{
    memset(rd,0,sizeof(rd));
    memset(p,-1,sizeof(p));
    num=0;
}
void add(int st,int en)
{
    rd[en]++;
    E[num].en=en;
    E[num].next=p[st];
    p[st]=num++;
}
bool check(int x,int y)
{
    return x>=1&&x<=n&&y>=1&&y<=m;
}
int ID(int x,int y)
{
    return (x-1)*m+y;
}
int dfn[nn*nn],low[nn*nn];
int cnt;
bool insta[nn*nn];
stack<int>sta;
bool use[nn*nn][15];
bool vis[nn*nn];
void dfs(int id)
{
    sta.push(id);
    insta[id]=true;
    dfn[id]=low[id]=++cnt;
    int i,w;
    for(i=p[id];i+1;i=E[i].next)
    {
        w=E[i].en;
        if(dfn[w]==-1)
        {
            dfs(w);
            low[id]=min(low[id],low[w]);
        }
        else if(insta[w])
        {
            low[id]=min(low[id],dfn[w]);
        }
    }
    if(dfn[id]==low[id])
    {
        while(1)
        {
            int ix=sta.top();
            if(ix!=id)
            {
                vis[ix]=false;
                rd[id]=0;
            }
            sta.pop();
            insta[ix]=false;
            use[id][sz[ix]]=true;
            if(ix==id)
                break;
        }
    }
}
void tarjan()
{
    memset(dfn,-1,sizeof(dfn));
    memset(insta,false,sizeof(insta));
    memset(use,false,sizeof(use));
    memset(vis,true,sizeof(vis));
    cnt=0;
    int i,j,w;
    for(i=1;i<=n*m;i++)
    {
        if(dfn[i]==-1)
        {
            dfs(i);
        }
    }
}
bool solve(int id,int ix)
{
    if(ix==-1)
        return true;
    int i,w;
    bool re=false;
    for(i=p[id];i+1;i=E[i].next)
    {
        w=E[i].en;
        if(!vis[w])
            continue;
        if(use[w][s[ix]-'0'])
        {
            re=re||solve(w,ix-1);
        }
        else
        {
            re=re||solve(w,ix);
        }
    }
    return re;
}
int main()
{
    int i,j;
    while(scanf("%d%d%d",&n,&m,&q)!=EOF)
    {
        for(i=1;i<=n;i++)
        {
            scanf("%s",stu[i]);
            for(j=0;j<m;j++)
            {
                tu[i][j+1]=stu[i][j]-'0';
                sz[ID(i,j+1)]=tu[i][j+1];
            }
        }
        for(i=0;i<=9;i++)
        {
            scanf("%d%d",&a[i],&b[i]);
        }
        init();
        for(i=1;i<=n;i++)
        {
            for(j=1;j<=m;j++)
            {
                if(check(i+a[tu[i][j]],j+b[tu[i][j]]))
                {
                    add(ID(i+a[tu[i][j]],j+b[tu[i][j]]),ID(i,j));
                }
            }
        }

        tarjan();
        while(q--)
        {
            scanf("%s",s);
            int ls=strlen(s);
            for(i=1;i<=n*m;i++)
            {
                if(rd[i]==0)
                {
                    int fuck=ls;
                    while(fuck>=1)
                    {
                        if(use[i][s[fuck-1]-'0'])
                        {
                            fuck--;
                        }
                        else
                            break;
                    }
                    if(fuck==0)
                    {
                        puts("YES");
                        break;
                    }
                    if(solve(i,fuck-1))
                    {
                        puts("YES");
                        break;
                    }
                }
            }
            if(i>n*m)
            {
                puts("NO");
            }
        }
    }
    return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值