目录
一:1-11周的总结
二:优先队列并查集拓扑排序做题和复现赛总结
三:最小生成树和最短路总结
1:Dijkstra
2:Bellman-Ford
3:Floyd算法
1:纸上得来终觉浅,绝知此事要躬行。
参加程序设计竞赛这件事远远比自己想象的要难很多。就连最基础的STL,虽然看起来就那么几个操作,但真正拿去做题,写作业,就感觉要真正用好STL,需要花费非常大的功夫。
2:做一件事就要把一件事情做好,必须把经历集中于一件事情,否则将会一事无成。学校的活动固然是丰富多彩的,但是大学四年的时光也是短暂的,本身就是出身于一所普通的本科学校,就更要多为自己的未来谋划,不能沉迷于眼前的享乐,更不能像自己的同学一样觉得这所学校很多年以前能和山大相提并论,自恃高人一等,要认清现实,这就是一所普普通通的高校,打铁还需自身硬,否则将会在4年之后什么也不是。
3:今天的事情不能够拖到明天,自从学习ACM程序设计以来,我的作业和任务都是日日清,很少有拖到第二天的情况。
4:学习要讲究方法,追求效率。我发现我们专业考试不会考出了课件和课后题上的题型,但是很多同学买了很多课外的资料做,放着课件和课本上的提视而不见,结果第一学年第一学期成绩很不理想。我想学习算法也是如此,我也在探索能提高效率的方法,比如更多的笔算。
5:不要做井底之蛙。我发现我身边很多同学充满了优越感,经常痛斥XX学校垃圾,XX学院垃圾,觉得自己学院各种各种厉害。当看到自己不想看到的东西时,就给自己找理由,把他说成好的,当看到别人或者别的学院,学校比自己好,就找理由骂它垃圾。我想这对我来说,是应该吸取教训的。我认为在任何学校,任何学院,都有翱翔的雄鹰。我很羡慕41届ICPC亚洲区域赛获得金牌的山东理工大学队伍--Rising RP,也很崇拜大一大二就你会做莫比乌斯反演的其他院校的选手,并在像他们学习。
1:通过做并查集的题目,和看并查集的题目,我感觉并查集简单的题目思路非常的相似,也很好做,种类并查集和带权并查集不是很好做,对于字符串类型的题来说,并查集可以和map相联系,用map存储字符串下标。并查集可以和贪心算法相结合,感觉各个题目就是合并的依据不同,很多题也是这个比较难思考。还有的题合并的时候需要同时维护其他数据,比如路径长度,集合中的元素数目等,有的题需要用逆向思维,删除改成增加,然后使用并查集合并求解,有的题先删除所有的节点,再重新增加,万变不离其宗,核心思想还是并查集。
2:拓扑排序我感觉比较的难做,很多题目我都不会做,可以说会做的没几个,感觉不是不会拓扑排序,而是不能理解题意,或者说是不能理解拓扑排序的依据,拓扑排序还需要多加练习。拓扑排序可以和DFS/BFS相结合,可以先排序再DFS,也可以同时进行,有些题存在负权问题,非常的棘手。
3:牛客网比赛,很多题看着好做,实际就做不出来,也暴露了自己优先队列学的不怎么样,并查集部分的题感觉还可以。甚至后面几道题,明明2周前做过,再写却还是很卡手,写不出来。通过这次比赛明白了,STL必须熟练才行。
单调队列保证队列中各个元素大小单调递减(即,最大元素在对头,最小的在队尾),同时每个元素的下标单调递增(按校标递增的顺序添加这点可以不用考虑)。这样便保证队首元素最大,而且更新的时候队首永远是当前最大。因此,这个队列需要在两头都可以进行删除,在队尾插入。 维护方法:在每次插入的时候,先判断队尾元素,如果不比待插入元素大就删除,不断删除队尾直到队尾元素大于待插入元素或者队空。删除的时候,判断队首,如 果队首元素下标小于当前段左边界就删除,不断删除队首直到队首元素下标大于等于当前段左边界(注意:这时队列肯定不为空),队首元素就是当前段的最优解。
#include
using namespace std;
#define N 100
struct edge {
int u, v, value;
}myedge[N * N];
int n, m, p[N];
bool cmp(const edge& p1, const edge& p2) {
return p1.value < p2.value;
}
int find(int x) {
return (p[x] == x) ? x : (p[x] = find(p[x]));
}
int main() {
while (scanf("%d%d", &n, &m) == 2) {
char a[2], b[2];
int i, x, y, sum = 0, value, counter = 0;
for (i = 0; i < m; i++) {
scanf("%s%s%d", a, b, &myedge[i].value);
myedge[i].u = a[0] - 'a';
myedge[i].v = b[0] - 'a';
}
for (i = 0; i < n; i++) p[i] = i;
sort(myedge, myedge + m, cmp);
for (i = 0; i < m; i++) {
value = myedge[i].value;
x = find(myedge[i].u);
y = find(myedge[i].v);
if (x != y) {
sum += value;
p[y] = x;
counter++;
if (counter >= n - 1) break;
}
}
printf("%d\n", sum);
}
return 0;
}
for(int i = 0; i < n; i++) dis[i] = INF;
dis[0] = 0;
for(int k = 0; k < n-1; k++) { //控制次数
for(int i = 0; i < m; i++) {
if(dis[v[i]] > dis[u[i]] + w[i])
dis[v[i]] = dis[u[i]] + w[i];
} }
每次仅对最短路程发生了变化的结点的相邻边执行操作, 效率可能会高一些.可以使用队列来维护这些点。
如果需要求任意两点之间的距离,不必调用n次Dijstra或 Bellman-ford算法,可以使用Floyd-Warshall算法。Floyd算法利用了动态规划,用d[i][j][k]表示从i到j,经过编号不超过k的点所得到的最短距离,则