Uva11882 Biggest Number 【dfs回溯+bfs剪枝】【习题7-15】

来源:互联网 发布:如何找pdf 知乎 编辑:程序博客网 时间:2024/05/21 11:36

题目:Biggest Number

题意:

在一个RC列(2≤RC≤15R*C≤30)的矩阵里有障碍物和数字格(包含19的数字)。 你可以从任意一个数字格出发,每次沿着上下左右之一的方向走一格,但不能走到障碍格中,也不能重复经过一个数字格,然后把沿途经过的所有数字连起来,问:能得到的最大整数是多少?

思路:

还是老套路,dfs寻找所有路径,累计筛选最大的数即可,恩,很简单嘛。。。提交,TLE,呵呵,数字太大了!所以剪枝来了。。。

本题的连接数字已经超出了long long型,所以需要用字符串,所以首先比较的是长度,长度越长即越大!!!

剪枝1:当前已经连接的数的个数+还可连接的数的个数  < 当前最优解的长度,直接剪枝,没有必要再搜索下去!

怎么找还可连接的数的个数呢?   利用bfs,使用当前的标记数组,搜索出还可连接的个数即可。

剪枝2:当前已经连接的数的个数+还可连接的数的个数  == 当前最优解的长度时,比较大小,小直接剪掉。只比较当前连接的数的长度这些数字,将当前的串加上一个比数字字符大的字符即可。因为有可能当前串和最优解的都相等,但最优解串长,就直接认为是最优解大了,其实当前还不确定,所有再当前串的下一位加一个大于数字的字符,这样避免了相等也被剪枝的情况!
筛选最优解:每次递归时将当前串进行与最优解比较长度,如果相等的话再比较大小。

参考:ECNU_ZR博客

代码:

#include <iostream>#include <cstdio>#include <cstring>#include <algorithm>#include <queue>using namespace std;typedef long long LL;const int maxn = 20 + 5;const int dx[] = {0,0,1,-1};const int dy[] = {1,-1,0,0};char g[maxn][maxn];int visitD[maxn][maxn],visitB[maxn][maxn];int r,c;string ans,temp;struct Node{    int x,y;    Node(int x = 0,int y = 0):x(x),y(y){}};queue<Node>Q;inline bool scope(int tx,int ty){//判断边界    if(tx < 0 || tx >= r || ty < 0 || ty >= c) return true;    return false;}int bfs(int x,int y){//查找当前(x,y)开始还可以连接几个数字    memcpy(visitB,visitD,sizeof(visitD));//将当前dfs标记数组赋给bfs标记数组    visitB[x][y] = 1;//标记起点    while(!Q.empty()) Q.pop();//清空队列    Node pre;    Q.push(Node(x,y));//将起点入队    int cnt = 0;//记录经过几个点    while(!Q.empty()){        pre = Q.front();Q.pop();        for(int i=0;i<4;i++){            int tx = pre.x + dx[i] , ty = pre.y + dy[i];            if(scope(tx,ty)) continue;            if(g[tx][ty] != '#' && !visitB[tx][ty]){                visitB[tx][ty] = 1;                Q.push(Node(tx,ty));                cnt++;//记录连接到的数字个数            }        }    }    return cnt;//返回剩余的连接个数}void update(const string &s){//更新最优解:当前长度长或长度相等数字大时更新    if(s.size() > ans.size() || s.size() == ans.size() && s > ans) ans = s;}void dfs(int d,int x,int y,string sum){//回溯枚举所有连接路径    int len = bfs(x,y);//当前点还可连接的数的个数    if(d + len < ans.size()) return;//剪枝:当前的长度+还可连接的长度 < 最优值的长度,没有必要再进行下去    if(d + len == ans.size() && sum+"a" < ans) return;//剪枝:长度相等,但没有最优解大,没有不必了!    update(sum);//更新最优解    for(int i=0;i<4;i++){        int tx = x + dx[i] , ty = y + dy[i];        if(scope(tx,ty)) continue;        if(!visitD[tx][ty] && g[tx][ty] != '#'){            visitD[tx][ty] = 1;            dfs(d+1,tx,ty,sum + g[tx][ty]);            visitD[tx][ty] = 0;        }    }}inline void solve(){    ans = "";    for(int i=0;i<r;i++)        for(int j=0;j<c;j++)            if(g[i][j] != '#'){                memset(visitD,0,sizeof(visitD));                visitD[i][j] = 1;//注意:将起点标记                temp = g[i][j];                dfs(1,i,j,temp);            }    cout << ans << endl;}int main(){    while(scanf("%d%d",&r,&c)!=EOF && r && c){        for(int i=0;i<r;i++) scanf("%s",g[i]);        solve();    }    return 0;}


0 0
原创粉丝点击