CCF 习题 201512-4 送货 (并查集 + DFS 找欧拉道路)

20 篇文章 0 订阅
7 篇文章 0 订阅

大体题意:

要求从1号出发,一笔画经过所有的路,问是否有解,并打印字典序最小的解?

思路:

显然是无向图的欧拉道路!

先判连通,直接用并查集了,不连通直接-1了

连通的话,在看看每个点的度数,当奇点的个数不是0  并且不是2  肯定是-1

如果是2  的话,1号结点是偶数度数的话也是-1

否则我们就可以从1号结点直接dfs找路了!

注意:

不能再dfs之前就输出路径,这样是不对的 = =  这样只得了20分!

因为这个点可能不合适,因此我们要用的stack 最后输出stack即可!

详细见代码:

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
#define mr make_pair
#include<stack> 
using namespace std;
const int maxn = 10001;
bool g[maxn][maxn];
int n,m;
int num[10001];
bool vis[maxn][maxn];
vector<int>G[maxn];
int fa[maxn];
stack<int>sk;
int find(int x){
	return fa[x] == x ? fa[x] : fa[x] = find(fa[x]);
}
void add(int x,int y){
	int xx = find(x);
	int yy = find(y);
	if (xx != yy)fa[yy] = xx;
}
void dfs(int k){
	int len = G[k].size();
	for (int i = 0; i < len; ++i){
		int t = G[k][i];
		if (!vis[k][t]){
			vis[k][t] = vis[t][k] = 1;
			dfs(t);
			sk.push(t);
		}
	}
	
}
int main(){
	scanf("%d %d", &n, &m);
	for (int i = 0; i <= n; ++i)fa[i] = i;
	for (int i = 0; i < m ;++i){
		int u,v;
		scanf("%d %d",&u,&v);
		add(u,v);
		G[u].push_back(v);
		G[v].push_back(u);
		num[u]++;
		num[v]++;
	}
	for (int i = 1; i <= n; ++i)sort(G[i].begin(),G[i].end());
	bool GO = 1;
	int t1 = find(1);
	for (int i = 1; i <= n; ++i){
		if (find(i) != t1){
			GO = 0;
			break;
		}
	}
	if (!GO)return 0 * puts("-1");
	int sum = 0;
	for (int i = 1; i <= n; ++i)if (num[i] & 1)++sum;
	if (sum != 0 && sum != 2)return 0 * puts("-1");
	if (sum == 2 && (num[1] & 1) == 0) return 0 * puts("-1");
	printf("1");
	dfs(1);
	while(!sk.empty()){
		printf(" %d",sk.top());
		sk.pop();
	}
	puts("");
	return 0;
}

问题描述
试题编号:201512-4
试题名称:送货
时间限制:1.0s
内存限制:256.0MB
问题描述:
问题描述
  为了增加公司收入,F公司新开设了物流业务。由于F公司在业界的良好口碑,物流业务一开通即受到了消费者的欢迎,物流业务马上遍及了城市的每条街道。然而,F公司现在只安排了小明一个人负责所有街道的服务。
  任务虽然繁重,但是小明有足够的信心,他拿到了城市的地图,准备研究最好的方案。城市中有n个交叉路口,m条街道连接在这些交叉路口之间,每条街道的首尾都正好连接着一个交叉路口。除开街道的首尾端点,街道不会在其他位置与其他街道相交。每个交叉路口都至少连接着一条街道,有的交叉路口可能只连接着一条或两条街道。
  小明希望设计一个方案,从编号为1的交叉路口出发,每次必须沿街道去往街道另一端的路口,再从新的路口出发去往下一个路口,直到所有的街道都经过了正好一次。
输入格式
  输入的第一行包含两个整数n, m,表示交叉路口的数量和街道的数量,交叉路口从1到n标号。
  接下来m行,每行两个整数a, b,表示和标号为a的交叉路口和标号为b的交叉路口之间有一条街道,街道是双向的,小明可以从任意一端走向另一端。两个路口之间最多有一条街道。
输出格式
  如果小明可以经过每条街道正好一次,则输出一行包含m+1个整数p 1, p 2, p 3, ..., p m +1,表示小明经过的路口的顺序,相邻两个整数之间用一个空格分隔。如果有多种方案满足条件,则输出字典序最小的一种方案,即首先保证p 1最小,p 1最小的前提下再保证p 2最小,依此类推。
  如果不存在方案使得小明经过每条街道正好一次,则输出一个整数-1。
样例输入
4 5
1 2
1 3
1 4
2 4
3 4
样例输出
1 2 4 1 3 4
样例说明
  城市的地图和小明的路径如下图所示。
样例输入
4 6
1 2
1 3
1 4
2 4
3 4
2 3
样例输出
-1
样例说明
  城市的地图如下图所示,不存在满足条件的路径。
评测用例规模与约定
  前30%的评测用例满足:1 ≤ n ≤ 10, n-1 ≤ m ≤ 20。
  前50%的评测用例满足:1 ≤ n ≤ 100, n-1 ≤ m ≤ 10000。
  所有评测用例满足:1 ≤ n ≤ 10000,n-1 ≤ m ≤ 100000。

题目《202305-5 闪耀巡航》是CCF CSP(中国大学生程序设计竞赛)的一个挑战题目,它通常涉及算法、数据结构和数学思维。不过,由于你提到的是Python和C++的满分题解,这说明我们需要考虑如何高效地使用这两种语言解决此问题。 闪耀巡航的问题描述一般涉及到路径优化、动态规划或者是图论中的最短路径问题。你需要帮助一个机器人在网格上到从起点到终点的最优路线,可能会有光照限制或其他规则影响行进路径。 在Python中,可以利用Pandas处理二维数组,然后使用深度优先搜索(DFS)、广度优先搜索(BFS),或者更复杂一些,如Bellman-Ford算法来求解最短路径。记得检查边界条件和可能存在的循环引用问题。 C++方面,可以使用STL中的vector和list等容器,结合dfs函数或者Dijkstra算法(如果允许的话)。C++的迭代器和模板元编程能提高代码效率,但需要对数据结构和算法有深入理解。 以下是简化的步骤: 1. **分析问题**:明确输入格式,理解光照、障碍物等因素的影响。 2. **数据结构**:用二维数组表示地图,定义状态转移方程。 3. **选择策略**:如果是简单的遍历,用DFS;复杂一点的情况,考虑动态规划或者图搜索算法。 4. **编写代码**:递归或迭代实现算法,注意优化边界处理和空间复杂度。 5. **测试**:用样例数据验证算法是否正确,并尝试多种情况验证其鲁棒性。 至于具体的代码,这里给出一个大致框架,但因为竞赛题目细节未提供,无法给出完整的解答: ```cpp #include <iostream> using namespace std; // 用二维数组表示地图,值代表路径长度 int map[grid_size][grid_size]; // 动态规划或搜索函数 int shortestPath(int startRow, int startCol) { // 代码实现... } int main() { // 输入读取、初始化地图 // 调用shortestPath函数并打印结果 cout << shortestPath(0, 0) << endl; return 0; } ```
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值