• 2020.7.31 模拟赛 题解


    T1 营救

    题目描述

    铁塔尼号遇险了!他发出了求救信号。距离最近的哥伦比亚号收到了讯息,时间就是生命,必须尽快 赶到那里。

    通过侦测,哥伦比亚号获取了一张海洋图。这张图将海洋部分分化成 n*n 个比较小的单位,其中用 1 标明的是陆地,用 0 标明是海洋。船只能从一个格子,移到相邻的四个格子。

    为了尽快赶到出事地点,哥伦比亚号最少需要走多远的距离。

    • 输入格式:
      第一行为 n,下面是一个 n*n 的 0、1 矩阵,表示海洋地图。

      最后一行为四个小于 n 的整数,分别表示哥伦比亚号和铁塔尼号的位置。

    • 输出格式:
      哥伦比亚号到铁塔尼号的最短距离,答案精确到整数。

    样例输入
    3
    001
    101
    100
    1 1 3 3
    
    样例输出
    4
    
    数据范围与提示

    N<=1000

    AC代码
    // BFS板题 
    #include <cstdio>
    #include <queue>
    using namespace std;
    
    const int MAXN = 1005;
    int mp[MAXN][MAXN]; // 存图 
    int n; // 图的大小 
    struct node {
    	int x, y; // 坐标 
    };
    bool vis[MAXN][MAXN]; // 判断当前位置是否走过 
    int dx[5] = {0, 1, 0, -1};
    int dy[5] = {1, 0, -1, 0}; // 四个方向 
    node st, ed; // 起始点和终点 
    int ans[MAXN][MAXN]; // ans[i][j]表示到(i,j)需要的最短路程 
    
    void bfs() { // 宽搜 
    	queue<node> q;
    	q.push(st);  
    	vis[st.x][st.y] = true; 
    	while(!q.empty()) {  
    		node cur = q.front();
    		q.pop();
    		for(int i = 0; i < 4; i++) {  
    			int cx = cur.x + dx[i];
    			int cy = cur.y + dy[i];
    			if(cx < 1 || cx > n) continue;
    			if(cy < 1 || cy > n) continue;
    			// 如果下一个点不合法,找下一个方向 
    			if(vis[cx][cy] == false && mp[cx][cy] == 0) {
    				// 如果没走过,且为海洋 
    				vis[cx][cy] = true; // 标记下一个点为走过 
    				node nxt;
    				nxt.x = cx;
    				nxt.y = cy;
    				ans[nxt.x][nxt.y] = ans[cur.x][cur.y] + 1;  // 更新答案 
    				if(nxt.x == ed.x && nxt.y == ed.y) { 
    				// 如果下一个点就是终点?直接输出 
    					printf("%d", ans[ed.x][ed.y]);
    					return ;
    				} 
    				q.push(nxt); // 入队 
    			}
    		}
    	}
    	return ;
    }
    
    int main() {
    	scanf ("%d", &n);
    	for(int i = 1; i <= n; i++) {
    		char s[MAXN];
    		scanf ("%s", s + 1);
    		for(int j = 1; j <= n; j++) 
    			mp[i][j] = s[j] - '0';
    	}
    //	for(int i = 1; i <= n; i++) {
    //		for(int j = 1; j <= n; j++) 
    //			printf("%d ", mp[i][j]);
    //		puts(" ");
    //	}
    	scanf ("%d %d %d %d", &st.x, &st.y, &ed.x, &ed.y);
    	bfs();
    	return 0; 
    }
    

    T2 关系网络

    题目描述

    有 n 个人,他们的编号为 1~n,其中有一些人相互认识,现在 x 想要认识 y,可以通过他所认识的人来认识更多的人(如果 a 认识 b,b 认识 c,那么 a 可以通过 b 来认识 c),求出 x 最少需要通过多少人才能认识 y。

    • 输入格式
      第 1 行 3 个整数 n、x、y,2≤n≤100; 接下来的 n 行是一个 n×n 的邻接矩阵, a[i][j]=1 表示 i 认识 j,a[i][j]=0 表示不认识。 保证 i=j 时,a[i][j]=0,并且 a[i][j]=a[j][i]。

    • 输出格式
      一行一个整数,表示 x 认识 y 最少需要通过的人数。数据保证 x 一定能认识 y。

    输入样例

    5 1 5
    0 1 0 0 0
    1 0 1 1 0
    0 1 0 1 0
    0 1 1 0 1
    0 0 0 1 0

    输出样例

    2

    AC代码
    // 可以看作是求一个最短路
    // 他需要通过多少人才能认识某个其他人
    // 其实就是他最少需要经过多少个点才能到达终点 
    #include <cstdio>
    #include <cstring>
    using namespace std;
    
    const int MAXN = 105;
    int cost[MAXN][MAXN];
    // 利用邻接矩阵存图 
    int dist[MAXN]; // 最短路 
    bool vis[MAXN]; // 红蓝点集 
    int n, x, y;
    
    void dijkstra() { // 最短路dijkstra算法 
    	memset(dist, 0x3F, sizeof dist);
    	// 初值为最大,因为我们要找最小值 
    	dist[x] = 0;
    	for(int i = 1; i <= n; i++) {
    		int mi = 0x3F3F3F3F, k = 0;
    		for(int j = 1; j <= n; j++) { // 找到最小值 
    			if(!vis[j] && dist[j] < mi) {
    				mi = dist[j];
    				k = j;
    			}
    		}
    		vis[k] = true;
    		// 加入红点集 
    		for(int j = 1; j <= n; j++)
    			if(cost[k][j] != 0 && dist[j] > dist[k] + 1)
    			// 如果有边,且可以进行松弛,就直接松弛即可 
    				dist[j] = dist[k] + 1;
    	}
    	return ;
    }
    
    int main() {
    	scanf ("%d %d %d", &n, &x, &y);
    	for(int i = 1; i <= n; i++) 
    		for(int j = 1; j <= n; j++) {
    			int w;
    			scanf ("%d", &w);
    			cost[i][j] = w;
    			cost[j][i] = w;
    			// 双向存边 
    		}
    	dijkstra();
    	if(x != y) printf("%d ", dist[y] - 1); 
    	// 减去第一条边,就是经过的点数 
    	else printf("0");
    	return 0;
    }
    

    T3 寻找道路

    题目描述

    在有向图G中,每条边的长度均为1 ,现给定起点和终点,请你在图中找一条从起点到终点的路径,该路径满足以下条件:

    路径上的所有点的出边所指向的点都直接或间接与终点连通。
    在满足条件1的情况下使路径最短。
    注意:图G中可能存在重边和自环,题目保证终点没有出边。

    请你输出符合条件的路径的长度。

    • 输入格式
      第一行有两个用一个空格隔开的整数 n 和 m,表示图有 n 个点和 m 条边。

    接下来的 m 行每行 2 个整数 x, y,之间用一个空格隔开,表示有一条边从点 x 指向点 y。

    最后一行有两个用一个空格隔开的整数 s, t,表示起点为 s,终点为t 。

    • 输出格式
      输出只有一行,包含一个整数,表示满足题目描述的最短路径的长度。如果这样的路径不存在,输出 -1。
    样例输入 1
    3 2
    1 2
    2 1
    1 3
    
    样例输出 1
    -1
    
    样例输入 1
    6 6
    1 2
    1 3
    2 6
    2 5
    4 5
    3 4
    1 5
    
    样例输出 2
    3
    
    AC代码
    // 在跑最短路之前,标记一下哪些点可以走,哪些不可以走
    // 也就是以终点为起点,跑一遍dfs,在枚举每个点
    // 看它们联通的点是否都和终点联通 
    #include <cstdio>
    #include <cstring>
    #include <vector>
    using namespace std;
    
    const int MAXN = 10005;
    vector<int> s[MAXN];
    vector<int> t[MAXN]; // 反向存边 
    bool vis[MAXN]; // dijkstra 红蓝点集 
    bool flag[MAXN]; // 是否与终点联通 
    bool p[MAXN]; // 是否能走 
    int dist[MAXN];
    int n, m, S, T; // 点数n,边数m,起点S,终点T 
    
    void dfs(int i) { // 从终点开始搜索 
    	flag[i] = true;  
    	for(int j = 0; j < t[i].size(); j++) // 枚举当前点连接的边 
    		if(flag[t[i][j]] == false) // 如果没走过 
    			dfs(t[i][j]); // 走过去 
    	return ;
    }
    
    void dijkstra() { // 最短路dijkstra算法 
    	memset(dist, 0x3f, sizeof dist);
    	// 初值为最大,因为我们要找最小值
    	dist[S] = 0;
    	for(int i = 1; i <= n; i++) {
    		int mi = 0x3f3f3f3f, k = 0;
    		for(int j = 1; j <= n; j++) {
    			if(!vis[j] && dist[j] < mi) { // 找到最小值 
    				mi = dist[j];
    				k = j;
    			}
    		}
    		// 加入红点集 
    		vis[k] = true;
    		for(int j = 0; j < s[k].size(); j++) {
    			int v = s[k][j];
    			if(dist[v] > dist[k] + 1 && p[v] == true)
    			// 如果可以走,且可以进行松弛,就直接松弛即可 
    				dist[v] = dist[k] + 1;
    		}
    	}
    	return ;
    }
    
    int main() {
    	scanf ("%d %d", &n, &m); 
    	for(int i = 1; i <= m; i++) {
    		int x, y;
    		scanf ("%d %d", &x, &y);
    		s[x].push_back(y);
    		t[y].push_back(x);
    	}
    	scanf ("%d %d", &S, &T);
    	p[T] = true;
    	dfs(T);
    	for(int i = 1; i <= n; i++) { // 枚举每个点 
    		int tot = 0;
    		for(int j = 0; j < s[i].size(); j++) { // 枚举与这个点相连的边 
    			if(flag[s[i][j]] == true) tot++; 
    			// 更新一下有多少条边连接的点与终点联通 
    		}
    		if(tot == s[i].size() && tot != 0) p[i] = true;
    		// 如果都与终点联通说明这个点可以走 
    	}
    //	printf("
    ");
    //	for(int i = 1; i <= n; i++) printf("%d %d
    ", i, p[i]);
    //	printf("
    ");
    	dijkstra();	
    	if(dist[T] == 0x3f3f3f3f) printf("-1"); // 不能到达,输出-1 
    	else printf("%d", dist[T]); // 输出到终点的最短路 
    	return 0;
    } 
    
  • 相关阅读:
    编写高质量代码改善C#程序的157个建议——建议7: 将0值作为枚举的默认值
    编写高质量代码改善C#程序的157个建议——建议6: 区别readonly和const的使用方法
    编写高质量代码改善C#程序的157个建议——建议5: 使用int?来确保值类型也可以为null
    编写高质量代码改善C#程序的157个建议——建议4: TryParse比Parse好
    基于cookie实现用户验证
    页面分页自定义插件
    DOM详习讲解
    HTML标签详细讲解
    Tornado模板配置
    biginteger转Long
  • 原文地址:https://www.cnblogs.com/Chain-Forward-Star/p/13868197.html
Copyright © 2020-2023  润新知