头图

Red and Black

There is a rectangular room, covered with square tiles. Each tile is colored either red or black. A man is standing on a black tile. From a tile, he can move to one of four adjacent tiles. But he can't move on red tiles, he can move only on black tiles.

Write a program to count the number of black tiles which he can reach by repeating the moves described above.
Input
The input consists of multiple data sets. A data set starts with a line containing two positive integers W and H; W and H are the numbers of tiles in the x- and y- directions, respectively. W and H are not more than 20.

There are H more lines in the data set, each of which includes W characters. Each character represents the color of a tile as follows.

'.' - a black tile
'#' - a red tile
'@' - a man on a black tile(appears exactly once in a data set)
Output
For each data set, your program should output a line which contains the number of tiles he can reach from the initial tile (including itself).
Sample Input
6 9
....#.
.....#
......
......
......
......
......
井@...#
.#..#.
11 9
.#.........
.#.#######.
.#.#.....#.
.#.#.###.#.
.#.#..@#.#.
.#.#####.#.
.#.......#.
.#########.
...........
11 6
..#..#..#..
..#..#..#..
..#..#..###
..#..#..#@.
..#..#..#..
..#..#..#..
7 7
..#.#..
..#.#..

.

...@...

.

..#.#..
..#.#..
0 0
Sample Output
45
59
6
13

下面是分别用广度优先搜索和深度优先搜索的解决方案

//(图论(广搜)) 
#include<iostream>
#include<algorithm>
#include<string>
#include<string.h>
#include<cstdio>
#include<queue>
#include<stack> 
#include<set> 
#include<vector> 
using namespace std;
struct node{
    int x,y;//结构体变量的横纵坐标 
};
int n,m,ans;//输入字符图形行数和列数 
char s[25][25];//字符型邻接矩阵  
int dis[4][2] = {0,1,0,-1,1,0,-1,0};//移动 数组,2个数为一组,模拟横纵坐标变化的过程,如0,1表示横坐标不变,纵坐标加1,即向上移动 
void bfs(int dx,int dy){
    queue<node>q;
    node start,next;
    start.x = dx;
    start.y = dy;
    s[start.x][start.y] = '#';//先把起点位置设为'#' 
    q.push(start);//将该点入队 
    while(!q.empty()) {
        start = q.front();//将队头元素赋值给start,以便后面搜索其相邻元素 
        q.pop();//队头元素出队 
        for(int i = 0; i < 4; i++){//遍历该点四个方位邻接点 
            next.x = start.x + dis[i][0];//进行横纵坐标变化模拟移动 
            next.y = start.y + dis[i][1];
            if(s[next.x][next.y] == '#'|| next.x > n || next.x <1|| next.y > m ||next.y <1){//移动到尽头或者'#'处返回
//            if(s[next.x][next.y] == '#'|| next.x > n || next.y > m){ 
                continue;//跳过,不再执行后续递归 
            }
            s[next.x][next.y] ='#';//访问过就标记为#
            ans++;
            q.push(next); 
        }
        /*for(int dx = -1;dx <= 1;dx++){//可模拟8个方位的移动变化 
            for(int dy = -1;dy <= 1;dy++)
        }*/
    } 
}
int main(){
    while(cin >> m >> n,m||n){
        int sx = 0,sy = 0;//起点的横纵坐标,统计.的数量的变量
        ans = 1;//因为其本身也要算上 
        for(int i = 1; i <= n; i++){
            scanf("%s",s[i] + 1);//此处一行字符 按照 一个字符串来存%s,本来是s[i],由于i从1开始,所以s[i]首地址也加1
            for(int j = 1; j <= m; j++){
                if(s[i][j] == '@'){//寻找起始点的位置(横纵坐标) 
                    sx = i;
                    sy = j;
                    break; 
                }
            }     
        }
        bfs(sx,sy);//从起点开始深搜    
        cout << ans << endl;
    } 
    return 0;
} 
//(图论(深搜)) 
#include<iostream>
#include<algorithm>
#include<string>
#include<string.h>
#include<cstdio>
#include<queue>
#include<stack> 
#include<set> 
#include<vector> 
using namespace std;

int n,m;//输入字符图形行数和列数 
char s[25][25];//字符型邻接矩阵 
int sx,sy,ans;//起点的横纵坐标,统计.的数量的变量 
int dis[4][2] = {0,1,0,-1,1,0,-1,0};//移动 数组,2个数为一组,模拟横纵坐标变化的过程,如0,1表示横坐标不变,纵坐标加1,即向上移动 
void dfs(int x,int y){
    if(s[x][y] =='.'){
        ans++;
    }
    s[x][y] = '#';//找到.后 把.置为# 
    int xx,yy;
    for(int i = 0; i < 4; i++){//遍历该点四个方位邻接点 
        xx = x + dis[i][0];//进行横纵坐标变化模拟移动 
        yy = y + dis[i][1];
        if(s[xx][yy] == '#'|| xx > n || xx <1|| yy > m ||yy <1){//移动到尽头或者'#'处返回 
            continue;//不再执行dfs递归 
        }
        dfs(xx,yy);//递归遍历所有点的四个方向的点 
        /*for(int dx = -1;dx <= 1;dx++){//可模拟8个方位的移动变化 
            for(int dy = -1;dy <= 1;dy++)
        }*/
    } 
}
int main(){
    while(cin >> m >> n,m||n){
//        if(n==0&&m==0)
//            break;
        ans = 1;//因为其本身也要算上 
        for(int i = 1; i <= n; i++){
            scanf("%s",s[i] + 1);//此处一行字符 按照 一个字符串来存%s,本来是s[i],由于i从1开始,所以s[i]首地址也加1
            for(int j = 1; j <= m; j++){
                if(s[i][j] == '@'){//寻找起始点的位置(横纵坐标) 
                    sx = i;
                    sy = j;
                    break; 
                }
            }     
        }
        dfs(sx,sy);//从起点开始深搜    
        cout << ans << endl;
    } 
    return 0;
} 

另一种提前设置好移动数组的做法

//#include <iostream>
//#include <cstdio>
//using namespace std;
//int cnt,n,m;
//char map[30][30];
//int doto[4][2]={{1,0},{0,1},{-1,0},{0,-1}};
//void df(int i,int j)
//{
//    cnt++;
//    map[i][j]='#';//每次搜索完毕就赋值为‘#’,避免重复累加
//    //对于每一点,对其上下左右都进行搜索一遍
//    for(int k=0;k<4;k++)
//    {
//        int x=i+doto[k][0];
//        int y=j+doto[k][1];
//        if(x<n&&y<m&&x>=0&&y>=0&&map[x][y]=='.')//如果是黑砖则继续对黑砖进行四周搜索
//            df(x,y);
//    }
//    return ;
//
//}
//int main()
//{
//    int fi;
//    int fj;
//    while(cin>>m>>n)
//    {
//        if(n==0&&m==0)
//            break;
//        int i;
//        for(i=0;i<n;i++)
//        {
//            int j;
//            for(j=0;j<m;j++)
//            {
//                cin>>map[i][j];
//            if(map[i][j]=='@')//记录初始位置
//               {
//
//                   fi=i;
//                   fj=j;
//               }
//            }
//
//        }
//        cnt=0;
//        df(fi,fj);//从最初的位置进行搜索
//        cout<<cnt<<endl;
//    }
//    return 0;
//}

最短路径

在每年的校赛里,所有进入决赛的同学都会获得一件很漂亮的t-shirt。但是每当我们的工作人员把上百件的衣服从商店运回到赛场的时候,却是非常累的!所以现在他们想要寻找最短的从商店到赛场的路线,你可以帮助他们吗?

Input
输入包括多组数据。每组数据第一行是两个整数N、M(N<=100,M<=10000),N表示成都的大街上有几个路口,标号为1的路口是商店所在地,标号为N的路口是赛场所在地,M则表示在成都有几条路。N=M=0表示输入结束。接下来M行,每行包括3个整数A,B,C(1<=A,B<=N,1<=C<=1000),表示在路口A与路口B之间有一条路,我们的工作人员需要C分钟的时间走过这条路。
输入保证至少存在1条商店到赛场的路线。
Output
对于每组输入,输出一行,表示工作人员从商店走到赛场的最短时间
Sample Input
2 1
1 2 3
3 3
1 2 5
2 3 5
3 1 2
0 0
Sample Output
3
2

下面分别用图的广度优先算法和floyed算法,以及kruskal(邻接矩阵)、kruskal(邻接表)来解决这一问题

//(floyd求最短路径(邻接矩阵))
#include<iostream>
#include<algorithm>
#include<string>
#include<string.h>
#include<cstdio>
#include<queue>
#include<stack> 
#include<set> 
#include<vector> 
using namespace std;
#define INF 0x3f3f3f3f
const int maxn = 105;
int a[maxn][maxn];//邻接矩阵
int n,m;
void floyd(){
    int s = 1;//s可以定义为为任意一个点 
    for(int i = 1; i <= n; i++){//每个j和k经过i时都要判断,共有n个i(中间点) 
        for(int j = 1; j <= n; j++){
            if(a[i][j] != INF){
                for(int k = 1; k <= n; k++){
                    if(a[j][i] + a[i][k] < a[j][k]){//判断一下j经过0,1,2,3,4....n(i)后到k是否比j-k(直接)距离短 
                        a[j][k] = a[j][i] + a[i][k]; 
                    }
                }
            }
        }
    }
    printf("%d\n",a[s][n]);
} 
int main(){
    while(cin >> n >> m,m || n){
        memset(a,INF,sizeof(a));
        while(m--){
            int x,y,z;
            cin >> x >> y >> z;
            a[x][y] = a[y][x] = z;
        } 
        floyd();
    }
    return 0;
}
//(图论(广搜))
#include<iostream>
#include<algorithm>
#include<string>
#include<string.h>
#include<cstdio>
#include<queue>
#include<stack> 
#include<set> 
#include<vector> 
#define maxn 105
#define INF 0x3f3f3f3f
using namespace std;
int a[maxn][maxn];//表示两点距离的邻接矩阵 
bool vis[maxn];//判断是否被访问过
int dis[maxn];// 表示两点距离的数组(用作中间变量)
int n,m;//全局变量,dijkstra()函数中也要用到 
void dijk(int x,int y){
    for(int i = 1; i <= y; i++){//初始化dis,vis 
        dis[i] = a[x][i];//[1][1]到[1][n]
        vis[i] = false;//所有点都初始化为未访问过 
    }
    vis[x] = true;//把第一个值设为已访问
    int p = 0; 
    for(int i = 1; i <= y; i++){//为了每次循环都使minn恢复为INF 
    int minn = INF;
        for(int j = 1; j <= y; j++){
            if(vis[j] == 0 && dis[j] < minn){
                minn = dis[j];//找到最小的dis[],即1到1,1到2,1到3,1到4...中的最小路径 
                p = j;//把最小路径(1到某点)对应的点赋值给p 
            }
        }
        vis[p] = true;//把找到的点设为以访问 
        for(int j = 1; j <= y; j++){//判断经过p点到j点的距离 是否比 直接从1点到j点的距离短 
            if(vis[j] == 0 && dis[p] + a[p][j] < dis[j]){//满足条件就更新dis[j] 
                dis[j] = dis[p] + a[p][j];
            }
        } 
    } 
}
int main(){
    while(cin >> n >> m,m||n){
        int x,y,z;
        memset(a,INF,sizeof(a));//邻接矩阵数组初始化
        while(m--){
            cin >> x >> y >> z;
            a[x][y] = a[y][x] = z;
        }
        dijk(1,n);
        cout << dis[n] << endl;//输出1到最后一个点(此题为n)的额最短路径 
    } 
    return 0;
} 
////(dijkstra求最短路径(邻接矩阵))
//#include<iostream>
//#include<algorithm>
//#include<string>
//#include<string.h>
//#include<cstdio>
//#include<queue>
//#include<stack> 
//#include<set> 
//#include<vector> 
//#define maxn 105
//#define INF 0x3f3f3f3f
//using namespace std;
//int a[maxn][maxn];//表示两点距离的邻接矩阵 
//bool vis[maxn];//判断是否被访问过
//int dis[maxn];// 表示两点距离的数组(用作中间变量)
//int n,m;//全局变量,dijkstra()函数中也要用到 
//void dijk(int x,int y){
//    for(int i = 1; i <= y; i++){//初始化dis,vis 
//        dis[i] = a[x][i];//[1][1]到[1][n]
//        vis[i] = false;//所有点都初始化为未访问过 
//    }
//    vis[x] = true;//把第一个值设为已访问
//    int p;//中间变量,用做当前找到的最短路径对应的点 
//    for(int i = 1; i <= y; i++){//每次都会新增一点然后求最短路径,共y个点,循环y次 
//        int minn = INF;//每次循环都使minn恢复为INF
//        for(int j = 1; j <= y; j++){//找到下一个点 
//            if(vis[j] == 0 && dis[j] < minn){
//                minn = dis[j];//找到最小的dis[],即1到1,1到2,1到3,1到4...中的最小路径 
//                p = j;//把最小路径(1到某点)对应的点赋值给p 
//            }
//        }
//        vis[p] = true;//把找到的点设为以访问 
//        for(int j = 1; j <= y; j++){//判断经过p点到j点的距离 是否比 直接从1点到j点的距离短 
//            if(vis[j] == 0 && dis[p] + a[p][j] < dis[j]){//满足条件就更新dis[j] 
//                dis[j] = dis[p] + a[p][j];//计算加入p点后目前1到各点的最短路径 
//            }
//        } 
//    } 
//}
//int main(){
//    while(cin >> n >> m,m||n){
//        int x,y,z;
//        memset(a,INF,sizeof(a));//邻接矩阵数组初始化
//        while(m--){
//            cin >> x >> y >> z;
//            a[x][y] = a[y][x] = z;
//        }
//        dijk(1,n);//迪杰斯特拉求1-n的最短路径 
//        cout << dis[n] << endl;//输出1到最后一个点(此题为n)的额最短路径 
//    } 
//    return 0;
//} 
//(邻接表))
//#include<iostream>
//#include<algorithm>
//#include<string>
//#include<string.h>
//#include<cstdio>
//#include<queue>
//#include<stack> 
//#include<set> 
//#include<vector> 
//using namespace std;
//#define INF 0x3f3f3f3f
//int dis[105]; 
//bool vis[105];//访问标记数组 
//int n,m; 
//struct Edge{
//    int cost;//权值 
//    int next;//下一个点 
//};  
//vector<Edge> edge[105];//定义一个vector数组,来建立整个图
//void dijk(){
//    for(int i = 1; i <= n; i++){//距离和访问数组初始化 
//        vis[i] = false;
//        dis[i] = -1;
//    }
//    int newx = 1;//newx表示当前访问的点,从第一个点开始 
//    vis[newx] = true; //设置为已访问
//    dis[newx] = 0;//第一个点到本身为0
//    for(int i = 1; i <= n; i++){////每次都会新增一点然后求最短路径,共y个点,循环y次
//        for(int j = 0; j < edge[newx].size(); j++){//当前点在vector数组 
//            int newnext;
//            newnext = edge[newx][j].next;//把当前点(x)对应的vector数组(edge[newx])中包含的第j个结构的权值和对应的next点赋值给变量存储 
//            int newcost;
//            newcost = edge[newx][j].cost; 
//            if(vis[newnext]=true){
//                continue;//如果当前位置已经访问过,不再进行下面操作  
//            }
//            if(dis[newnext]== -1 || newcost + dis[newx] < dis[newnext]){//dis[newnext]== -1代表未被访问过 经过中间点到newnext点的距离 是否比 直接从1点到newnext点的距离短
//                dis[newnext] = newcost + dis[newx];//满足就更新dis[newnext] 
//            }
//        }
//        int minn;
//        minn = INF;
//        for(int j = 1; j <= n; j++){//找到下一个放进来的点
//            if(vis[j] || dis[j] == -1){//dis[j]== -1代表newx到j点仍然没有连通,那该点肯定加不进来,不用进行后续操作 
//                continue;//如果当前位置已经访问过,不再进行下面操作
//            }
//            if(dis[j] < minn){
//                minn = dis[j];//找到最小的dis[],即1到1,1到2,1到3,1到4...中的最小路径  
//                newx = j;//把找到的点加进来 
//            } 
//        }
//        vis[newx] = true; 
//    }
//    printf("%d\n",dis[n]); 
//}
//int main(){
////    while(scanf("%d %d",&n,&m) != EOF,m||n){
//    while(scanf("%d %d",&n,&m) != EOF){
//        if(m == 0 && n == 0){
//            break;
//        }
//        for(int i = 0; i < n; i++){
//            edge[i].clear();//vector是全局变量,每次循环需要清空 
//        }
//        for(int i = 0; i < m; i++){//建图(邻接表相互(x - y或y - x)的权值一样)
//            int x,y,z;
//            scanf("%d %d %d",&x,&y,&z);
//            Edge temp;//定义一个结构体中间量
//            temp.cost = z;//为这个量赋相应的值 
//            temp.next = y; 
//            edge[x].push_back(temp);//把下一个点为y的结构封装在vector数组edge里
//            temp.next = x;
//            edge[y].push_back(temp);//把下一个点为x的结构封装在vector数组edge里 
//        }
//        dijk(); 
//    } 
//    return 0;
//} 


沐小轲
9 声望0 粉丝

C++初学者