7-11 关键活动 (正反向拓扑排序)
https://pintia.cn/problem-sets/15/problems/719
输入样例:
7 8
1 2 4
1 3 3
2 4 5
3 4 3
4 5 1
4 6 6
5 7 5
6 7 2
输出样例:
17
1->2
2->4
4->6
6->7
#include <iostream>
#include <queue>
#include <cstring>
using namespace std;
#define N 105
#define INF 99999
int main() {
int n, m;
cin >> n >> m;
int map[N][N];
int indegree[N];
int outdegree[N];
int es[N];
int le[N];
memset(indegree, 0, sizeof(indegree));
memset(outdegree, 0, sizeof(outdegree));
memset(es, 0,sizeof(es));
for(int i = 1; i <= n; i++)
for(int j = 1; j <= n; j++)
if(i == j)
map[i][j] = 0;
else
map[i][j] = INF;
for(int i = 1; i <= n; i++)
le[i] = INF;
while(m--) {
int a, b, c;
cin >> a >> b >> c;
map[a][b] = c;
indegree[b]++;
outdegree[a]++;
}
queue<int> q;
for(int i = 1; i <= n; i++)
if(indegree[i] == 0) {
q.push(i);
indegree[i] = -1;
}
int cnt = 0;
while(!q.empty()) {
int l = q.front();
q.pop();
cnt++;
for(int i = 1; i <= n; i++) {
if(map[l][i] < INF) {
es[i] = max(es[i], es[l] + map[l][i]);
indegree[i]--;
}
if(indegree[i] == 0) {
q.push(i);
indegree[i] = -1;
}
}
}
if(cnt != n) {
cout << 0 << endl;
return 0;
}
int maxTime = 0;
int index = 0;
for(int i = 1; i <= n; i++)
if(maxTime < es[i]) {
maxTime = es[i];
index = i;
}
q = queue<int>();
for(int i = 1; i <= n; i++)
if(outdegree[i] == 0) {
q.push(i);
le[i] = maxTime;
outdegree[i] = -1;
}
while(!q.empty()) {
int l = q.front();
q.pop();
for(int i = 1; i <= n; i++) {
if(map[i][l] < INF) {
le[i] = min(le[i], le[l] - map[i][l]);
outdegree[i]--;
}
if(outdegree[i] == 0) {
q.push(i);
outdegree[i] = -1;
}
}
}
cout << maxTime << endl;
for(int i = 1; i <= n; i++)
for(int j = n; j >= 1; j--) // 逆序输出
if(i != j && map[i][j] == le[j] - es[i]) // map[i][j] < INF && map[i][j] == le[j] - es[i]
cout << i << "->" << j << endl;
return 0;
}
OK,关于这道题我有很多槽要吐,不过能够debug出来还是很棒的,经典的版子题
1.关于map[i][j]的初始化问题
for(int i = 1; i <= n; i++)
for(int j = 1; j <= n; j++)
if(i == j)
map[i][j] = 0;
else
map[i][j] = INF;
//......
for(int i = 1; i <= n; i++)
for(int j = n; j >= 1; j--) // 逆序输出
if(i != j && map[i][j] == le[j] - es[i]) // map[i][j] < INF && map[i][j] == le[j] - es[i]
cout << i << "->" << j << endl;
return 0;
如果我们在初始化map的时候将map[i][i] = 0,那么在之后计算le[j] - es[i]的时候便会出现map[i][i] = =le[i] - es[i]的情况,也就是会出现输出i->i的情况,所以会出错。
2. 多起点,多终点的测试点问题
参考数据集(参考文献: https://blog.csdn.net/qq_26437925/article/details/47976341)
输入样例 2
7 6
1 2 4
1 3 3
2 4 5
3 4 3
5 7 5
6 7 2
输出样例 2
9
1->2
2->4
把这个数据集的图画出来后并结合这个数据集输出,我得到了一个两个并不想连接的节点的连接路径,苦思冥想后终于发现在最一开始的代码中,我仅仅将多个终点中的一个终点再赋值为max(es[i]),而其他的终点的值仍然是INF,因此在再赋值le[i]的时候,需要将所有的出度为0的节点赋值为max(es[i]).
int maxTime = 0;
int index = 0;
for(int i = 1; i <= n; i++)
if(maxTime < es[i]) {
maxTime = es[i];
index = i;
}
q = queue<int>();
for(int i = 1; i <= n; i++)
if(outdegree[i] == 0) {
q.push(i);
le[i] = maxTime;
outdegree[i] = -1;
}
// ......
for(int i = 1; i <= n; i++)
for(int j = n; j >= 1; j--) // 逆序输出
if(i != j && map[i][j] == le[j] - es[i]) // map[i][j] < INF && map[i][j] == le[j] - es[i]
cout << i << "->" << j << endl;
----------
// 或者
int maxTime = 0;
int index = 0;
for(int i = 1; i <= n; i++)
if(maxTime < es[i]) {
maxTime = es[i];
index = i;
}
le[index] = maxTime;
q = queue<int>();
for(int i = 1; i <= n; i++)
if(outdegree[i] == 0) {
q.push(i);
outdegree[i] = -1;
}
// ......
for(int i = 1; i <= n; i++)
for(int j = n; j >= 1; j--) // 逆序输出
if(i != j &&map[i][j] < INF && map[i][j] == le[j] - es[i]) // map[i][j] < INF && map[i][j] == le[j] - es[i]
cout << i << "->" << j << endl;
- 逆序输出问题
这个就是纯粹的输出格式问题,当时想不通为什么第二个for循环中的j要逆序输出,后来查阅资料发现是题目要求.
参考了这位博主的博客:https://blog.csdn.net/rxq20081235/article/details/60766993
for(int i = 1; i <= n; i++)
for(int j = n; j >= 1; j--) // 逆序输出
if(i != j && map[i][j] == le[j] - es[i]) // map[i][j] < INF && map[i][j] == le[j] - es[i]
cout << i << "->" << j << endl;
7-32 哥尼斯堡的“七桥问题
https://pintia.cn/problem-sets/15/problems/859
输入样例1:
6 10
1 2
2 3
3 1
4 5
5 6
6 4
1 4
1 6
3 4
3 6
输出样例1:
1
输入样例2:
5 8
1 2
1 3
2 3
2 4
2 5
5 3
5 4
3 4
输出样例2:
0
明确欧拉回路的定义按部就班解答即可
欧拉回路: 1.连通图
2 .图中的每个节点的度均为偶数
使用并查集判断图联通,再用个for循环判断度的奇偶性即可.
#include <iostream>
using namespace std;
#define N 1005
int pre[N];
int degree[N];
int n, m;
int find(int x) {
if(x != pre[x])
return pre[x] = find(pre[x]);
return x;
}
void Union(int x, int y) {
int a = find(x);
int b = find(y);
if(a != b)
pre[a] = b;
return;
}
int main() {
cin >> n >> m;
for(int i = 1; i <= n; i++) {
pre[i] = i;
degree[i] = 0;
}
while(m--) {
int a, b;
cin >> a >> b;
degree[a]++;
degree[b]++;
Union(a, b);
}
int cnt = 0;
for(int i = 1; i <= n; i++)
if(pre[i] == i)
cnt++;
if(cnt > 1) {
cout << 0;
return 0;
}
for(int i = 1; i <= n; i++)
if(degree[i] % 2 != 0) {
cout << 0;
return 0;
}
cout << 1;
return 0;
}
// 这道题只要知道了定义解法就不是很难了,但是在第二遍做的时候,不知道为什么死活拿不到满分,于是按照原来的思路重写了一遍之后就AC了,代码与之前一致,理解不能这种怪现象.