cf374C Inna and Dima dfs判环+求最长链

本文介绍了一道关于在一个由DIMA字符组成的矩阵中寻找最长DIMA串的问题。通过建立图模型并使用DFS算法来判断是否存在环以及找到最长的DIMA串数量。文章详细解析了解决方案,并分享了优化DFS过程的经验。
摘要由CSDN通过智能技术生成

题目大意是有一个DIMA四种字母组成的矩阵,要在矩阵中找最长的DIMADIMADIMA……串,连接方式为四方向连接,问最长能找到多少DIMA。字母可以重复访问,如果DIMA串成环,即可以取出无限长的DIMA串,则输出特定字符串,若没有DIMA串,也输出另一特定字符串,否则输出最长多少DIMA串。

 

这是我大一暑假的时候做的,并且当时WA在第23组上,后来就没继续做这个题了,现在不想看大一的代码了。

重新想了一下,其实就是判图中是否有环,无环的话,DIMA的链最长多少,也就是找图中以D字母开头的最长链。

那么读入之后对D->I  I->M  M->A  A->D 进行建边,并判环以及求最长链即可。

 

我考虑判环和求最长链长度都可以通过DFS实现,所以就只写了一个DFS函数。

 

DFS当然是没有写错的,但是发现在第10组T了。想了一下,DFS总复杂度是O(n^2+m)的,m为边数,因为所有点和边都只会被DFS一次,我全部从D字母开始搜索。此时因为我判环有提前return的操作,会导致vis没有清空,因此我在每次DFS前有memset掉vis数组的操作。如果D特别多,则memset每次都是O(n^2)的复杂度,就会超时。我修改了一下,将DFS过程中的return前都将vis置为0,就不用memset了,于是就过了。

 

其实如果将判环和求最长链分开,或许就不会出现这样的问题,比如用拓扑序判环,肯定不会出现大量memset。判完环再求最长链,则已经知道图中没有环,DFS每个点必定只需要访问一次,就不需要memset了。

 

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 #define PB push_back
 4 #define MP make_pair
 5 typedef long long ll;
 6 const int mod = 1e9 + 7;
 7 const int INF = 0x3f3f3f3f;
 8 const double eps = 1e-8;
 9 const int maxn = 1e6 + 5;
10 
11 int n,m;
12 int xx[4] = {1,-1,0,0};
13 int yy[4] = {0,0,1,-1};
14 char s[1005][1005];
15 int id[1005][1005];
16 int dis[maxn];
17 int head[maxn],point[maxn<<2],nxt[maxn<<2],size;
18 int vis[maxn];
19 bool flag = false;
20 
21 void init(){
22     size = 0;
23     memset(head,-1,sizeof(head));
24     memset(dis,0,sizeof(dis));
25     memset(vis,0,sizeof(vis));
26     flag = false;
27 }
28 
29 void add(int a, int b){
30     point[size] = b;
31     nxt[size] = head[a];
32     head[a] = size++;
33 }
34 
35 void dfs(int s){
36     if(dis[s])return;
37     vis[s] = 1;
38     dis[s] = 1;
39     for(int i = head[s] ; ~ i ; i = nxt[i]){
40         int j = point[i];
41         if(vis[j]){flag = true;vis[s] = 0;return;}
42         dfs(j);
43         if(flag){vis[s] = 0;return;}
44         dis[s] = max(dis[s],dis[j]+1);
45     }
46     vis[s] = 0;
47 }
48 
49 int main(){
50     scanf("%d%d",&n,&m);
51     for(int i = 1 ; i <= n ; ++ i)scanf("%s",s[i]+1);
52     int cnt = 0;
53     for(int i = 1 ; i <= n ; ++ i){
54         for(int j = 1 ; j <= m ; ++ j){
55             id[i][j] = ++ cnt;
56         }
57     }
58     init();
59     for(int i = 1 ; i <= n ; ++ i){
60         for(int j = 1 ; j <= m ; ++ j){
61             for(int k = 0 ; k < 4 ; ++ k){
62                 int dx = i + xx[k];
63                 int dy = j + yy[k];
64                 if(dx < 1 || dx > n || dy < 1 || dy > m)continue;
65                 if(s[i][j] == 'D' && s[dx][dy] == 'I')add(id[i][j],id[dx][dy]);
66                 if(s[i][j] == 'I' && s[dx][dy] == 'M')add(id[i][j],id[dx][dy]);
67                 if(s[i][j] == 'M' && s[dx][dy] == 'A')add(id[i][j],id[dx][dy]);
68                 if(s[i][j] == 'A' && s[dx][dy] == 'D')add(id[i][j],id[dx][dy]);
69             }
70         }
71     }
72     int ans = 0;
73     for(int i = 1 ; i <= n ; ++ i){
74         for(int j = 1 ; j <= m ; ++ j){
75             if(s[i][j] != 'D')continue;
76             dfs(id[i][j]);
77             if(flag == true){
78                 printf("Poor Inna!\n");
79                 return 0;
80             }
81             if(dis[id[i][j]] > ans)ans = dis[id[i][j]];
82         }
83     }
84     ans /= 4;
85     if(ans)printf("%d\n",ans);
86     else printf("Poor Dima!\n");
87     return 0;
88 }
View Code

 

转载于:https://www.cnblogs.com/cenariusxz/p/9639306.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值