Biggest Number
UVA - 11882
题目大意:有一个R*C的矩阵,矩阵里面有1~9的数字(太好了不用处理前导0),或者是#(代表不能通过),先要从矩阵任意一点出发(之前英语抓鸡看成了边界,英语差的孩纸伤不起啊>_<),只能往上下左右四个方向移动,每个格子不能重复走,到达矩阵内任意一点。把这条路径的数字连起来变成一个很大的数字,求这个数字最大是什么。
思路:DP?记忆化搜索?30个点噢,时间吃得消内存都吃不消啦。所以呢?搜索。还是超时啊?剪枝啊。
剪枝1:假设当前答案为ans,那么当我们走到一个点(x, y)的时候,作一个小小的搜索预判。假设现在能从(x, y)走到的点,我们都能到达,这是最好的情况。设从(x, y)能走到的点数为maxlen,那么如果从出发点走到(x, y)经过的格子,加上maxlen,都没有ans的长度大,那么不管从(x, y)怎么搜,我们都不能取代我们现在的ans(长才是王道懂不懂),那么直接回溯,不要这个点了。这个剪枝效力还是不错的,但是还是TLE,我试过了QAQ。最近有点脑残,明明可以做一个数据测试一下非要交上去试一下……
剪枝2:同剪枝1,假设当前答案为ans,那么当我们走到一个点(x, y)的时候,搜到maxlen(同剪枝1),如果从出发点走到(x, y)经过的格子,加上maxlen,大于ans的长度,我们就只能继续搜了……如果等于呢?那么就再作一个最好预期的答案。把从(x, y)能走到的所有格子,从大到小排好序(我的代码是从小到大排序然后从后面开始取的……),都接在当前走到(x, y)的后面,这是从(x, y)可能搜到的最好的答案,如果这个都比ans要小,那么我们也就没有必要往下搜了,果断回溯。
思路:DP?记忆化搜索?30个点噢,时间吃得消内存都吃不消啦。所以呢?搜索。还是超时啊?剪枝啊。
剪枝1:假设当前答案为ans,那么当我们走到一个点(x, y)的时候,作一个小小的搜索预判。假设现在能从(x, y)走到的点,我们都能到达,这是最好的情况。设从(x, y)能走到的点数为maxlen,那么如果从出发点走到(x, y)经过的格子,加上maxlen,都没有ans的长度大,那么不管从(x, y)怎么搜,我们都不能取代我们现在的ans(长才是王道懂不懂),那么直接回溯,不要这个点了。这个剪枝效力还是不错的,但是还是TLE,我试过了QAQ。最近有点脑残,明明可以做一个数据测试一下非要交上去试一下……
剪枝2:同剪枝1,假设当前答案为ans,那么当我们走到一个点(x, y)的时候,搜到maxlen(同剪枝1),如果从出发点走到(x, y)经过的格子,加上maxlen,大于ans的长度,我们就只能继续搜了……如果等于呢?那么就再作一个最好预期的答案。把从(x, y)能走到的所有格子,从大到小排好序(我的代码是从小到大排序然后从后面开始取的……),都接在当前走到(x, y)的后面,这是从(x, y)可能搜到的最好的答案,如果这个都比ans要小,那么我们也就没有必要往下搜了,果断回溯。
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstdlib>
#include<map>
#include<cstring>
#include<queue>
#include<cmath>
#include <ctype.h>
using namespace std;
const int N = 33;
typedef long long LL;
const int inf = 0x3f3f3f3f;
const int maxn=33;
int dir[4][2]= {{-1,0},{1,0},{0,-1},{0,1}};
struct node
{
int len, a[N];
void clear1()
{
len=0;
}
void print()
{
for(int i=0; i<len; i++) printf("%d",a[i]);
printf("\n");
}
bool operator <(const node& A)const
{
if(len!=A.len) return len<A.len;
for(int i=0; i<len; i++)
{
if(a[i]!=A.a[i]) return a[i]<A.a[i];
}
return false;
}
};
char str[31][31];
node ans,now;
int vis1[N][N], vis2[N][N], can[N];
int maxlen(int x,int y)
{
int cnt=1;
memset(vis2,0,sizeof(vis2));
can[0]=(str[x][y]-'0');
vis2[x][y]=1;
queue<int>q;
q.push((x*maxn+y));
while(!q.empty())
{
int u=q.front();
q.pop();
x=u/maxn,y=u%maxn;
for(int i=0; i<4; i++)
{
int ax=x+dir[i][0], ay=y+dir[i][1];
if(!isdigit(str[ax][ay]) || vis1[ax][ay] || vis2[ax][ay]) continue;
can[cnt++]=(str[ax][ay]-'0');
q.push(ax*maxn+ay);
vis2[ax][ay]=1;
}
}
return cnt;
}
void dfs(int x,int y)
{
vis1[x][y]=1;
now.a[now.len++]=(str[x][y]-'0');
for(int i=0; i<4; i++)
{
int ax=x+dir[i][0], ay=y+dir[i][1];
if(!isdigit(str[ax][ay]) || vis1[ax][ay]) continue;
int k=maxlen(ax,ay);
if(now.len+k<ans.len) continue;
if(now.len+k==ans.len)
{
sort(can,can+k);
node tmp=now;
for(int j=k-1; j>=0; j--) tmp.a[tmp.len++]=can[j];
if(tmp<ans) continue;
}
dfs(ax,ay);
}
vis1[x][y]=0;
if(ans<now) ans=now;
now.len--;
return ;
}
int main()
{
int n, m;
while(scanf("%d %d", &n, &m),(n!=0&&m!=0))
{
ans.clear1(), now.clear1();
memset(str,0,sizeof(str));
for(int i=1; i<=n; i++) scanf("%s",&str[i][1]);
memset(vis1,0,sizeof(vis1));
for(int i=1; i<=n; i++)
for(int j=1; j<=m; j++)
if(isdigit(str[i][j])) dfs(i,j);
ans.print();
}
return 0;
}
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<vector>
#include<cmath>
#include <bits/stdc++.h>
using namespace std;
const int N = 50;
typedef long long LL;
const int inf = 0x3f3f3f3f;
int dir[4][2]= {{-1,0},{1,0},{0,-1},{0,1}};
int n, m, total;
char str[N][N],g[N][N],ans[100],stack1[100];
int maxn, flag;
struct node
{
int x,y;
} queue1[1000];
bool yes(int x,int y)
{
return x>=0&&x<n&&y>=0&&y<m; //该点是否在地图中,是就返回true
}
int bfs1(int x,int y) //(x,y)处往后还能搜索到多少位有效数字
{
node t;
char g[20][20];
for(int i=0; i<n; i++)strcpy(g[i],str[i]); //将g中的值赋为str
int head,tail; //队列前后”指针“
head=tail=0; //队列为空
t.x=x,t.y=y; //其实节点,用于入队
queue1[tail++]=t; //数组模拟队列
while(head<tail) //队列不为空
{
x=queue1[head].x;
y=queue1[head++].y; //取出队头元素,队头后移一位
for(int i=0; i<4; i++) //四面查找
{
int xx=x+dir[i][0];
int yy=y+dir[i][1];
if(!yes(xx,yy)||g[xx][yy]=='#')continue; //该点不在地图中,该点不可处理【不处理该点】
g[xx][yy]='#'; //要处理该点,标记,预防重处理
t.x=xx,t.y=yy; //记录情况
queue1[tail++]=t; //新节点入“队”
}
}
return head; //该次处理的点数
}
void dfs(int x,int y,int cnt)
{
if(maxn<cnt||(maxn==cnt&&flag==1))
{
stack1[cnt]='\0';
strcpy(ans,stack1);
maxn=cnt;
flag=0;
}
int len=bfs(x,y);
if(len+cnt-1<maxn||(len+cnt-1==maxn&&flag==-1)) return;
for(int i=0; i<4; i++)
{
int ax=x+dir[i][0], ay=y+dir[i][1];
if(ax<0||ax>=n||ay<0||ay>=m||str[ax][ay]=='#') continue;
if(flag!=1&&maxn==total&&ans[cnt]>str[ax][ay]) continue;
stack1[cnt]=str[ax][ay];
str[ax][ay]='#';
if(flag==0)
{
if(cnt>=maxn) flag=1;
else if(ans[cnt]>stack1[cnt]) flag=-1;
else if(ans[cnt]<stack1[cnt])flag=1;
else flag=0;
dfs(ax,ay,cnt+1);
flag=0;
}
else dfs(ax,ay,cnt+1);
str[ax][ay]=stack1[cnt];
}
return ;
}
int main()
{
while(scanf("%d %d", &n, &m),n||m)
{
total=0,maxn=1;
for(int i=0; i<n; i++)
{
scanf("%s",str[i]);
for(int j=0; j<m; j++) if(str[i][j]!='#') total++;
}
memset(ans,0,sizeof(ans));
for(int i=0; i<n; i++)
{
for(int j=0; j<m; j++)
{
if(str[i][j]=='#') continue;
if(maxn==total&&ans[0]>str[i][j]) continue;
stack1[0]=str[i][j];
str[i][j]='#';
if(ans[0]==stack1[0]) flag=0;
else if(ans[0]<stack1[0]) flag=1;
else flag=-1;
dfs(i,j,1);
str[i][j]=stack1[0];
}
}
cout<<ans<<endl;
}
return 0;
}