2014-12-26数据结构上机 解题报告

来源:互联网 发布:c语言编程需要什么软件 编辑:程序博客网 时间:2024/06/07 05:17


       也快期末考了,所以写点数据机构上机的解题报告,和一些思想,帮助一下大家复习,也帮助我自己复习一下。


首先Problem A的意思是给你一个有向的图,然后让你判断这个图上面是否有环。

我们第十一章的作业题里面,有一道题就是判断无向图是否有环的。

这两道题都可以是采用深度优先搜索(DFS)解决。dfs(u)表示我们传进去一个点u,u的所有边。c[]数组表示DFS过程中结点访问的状态,即c[u] = -1 表示该结点正在访问, c[u] = 1表示该结点已经被访问, c[u] = 0 表示结点没有被访问。那么在DFS过程中如果出现了c[v] == -1,就代表着出现了环。如果看不懂参考着代码来看。

详细看下面代码:

#include <iostream>#include <cstring> using namespace std; const int MAXN = 2505;int c[MAXN]; int G[MAXN][MAXN];  // 用数组表示图 G[u][v] = 1 说明 有一条 u->v 的边int n, m;int T;bool dfs(int u)    // DFS{    c[u] = -1;  //标记u结点正在访问    for (int v = 1; v <= n; ++v)  // 遍历u的所有边        if (G[u][v]) // 如果u->v有边        {            if (c[v] == -1) return false; // 说明这里的v结点在较早之前已经被标记了,也就说明存在一个环使得 v->...->u->v;有环return false            else if (!c[v] && !dfs(v)) return false;  //!c[v] 为真是说c[v] == 0,也就是u没被访问过,那么就要进行dfs(v),如果dfs(v)返                                                     //回false说明有环,那么就又直接返回false        }    c[u] = 1; //遍历完所有u的边后,就把u标记为已访问    return true; // 说明没发现环,返回 true} bool hasCycle()   // 返回值依旧是颠倒是否,返回false说明有环,返回true说明无环。{   /*对于所有结点,都要进行DFS,因为①图可能不连通;②因为是有向的,环的起点可能不同。*/   for (int u = 1; u <= n; u++)          if (!c[u])            if (!dfs(u))                return false;    return true;}   int main(){    cin >> T;    while (T--) {        cin >> n >> m;        memset(G, 0, sizeof(G));  //初始化所有点都不连通。        memset(c, 0, sizeof(c));  //初始化所有点都未访问。        int u, v;        for (int i = 0; i < m; ++i) {  // 输入边            cin >> u >> v;            G[u][v] = 1;        }        if (hasCycle()) cout << "NO" << endl;    //这里颠倒是非的小细节不要在意 :)        else cout << "YES" << endl;    }    return 0;}/**************************************************************    Problem: 2298    User: 201330571073    Language: C++    Result: Accepted    Time:32 ms    Memory:26000 kb****************************************************************/

Problem B: Shortest Path

到目前为止,我都认为测试数据是错的,就又想上次那个链表题一样过不了。

这道题的意思是给你一个无向图G,一个起点S,一个终点T,让你找到从S到T的最短路径。

就是基础的单源最短路,用Dijkstra解决

Dijkstra的思想在书本上已经有讲,我讲不一定比它清楚,就不讲了。

下面给出我写Dijkstra的写法,也就是《算法竞赛入门经典》里面的写法。

#include <iostream>#include <cstring>using namespace std;#define  INF 0x3f3f3f3f   //定义无穷变量的一种机智的方法,可以百度了解一下0x3f3f3f3fint N, C, S, T;  int w[2505][2505];  // w[i][j] = INF 表示 i没有直接到j的边 w[i][j] = x表示 i到j有一条权值为x的边。int d[2505], v[2505];   // d[t] 表示 起点 s 到 t 的距离。 v[]是一个标记数组。void dij(int s)    // s 表示 图的起点。{memset(v, 0, sizeof(v));   // 清除所有点的标记for (int i = 1; i <= N; ++i) d[i] = (i == s ? 0 : INF); // 初始化d[s]的=0, 其他d[i] = INF;for (int i = 1; i <= N; ++i) {    // 循环遍历所有点。int x, m = INF;for (int y = 1; y <= N; ++y)      // 在所有为标记的点中,选出 d值最小的结点xif (!v[y] && d[y] <= m)m = d[x = y];v[x] = 1;  // 给结点 x 标记for (int y = 1; y <= N; ++y)  // 对于从 x 出发的所有边(x,y)更新d[y] = min {d[y], d[x] + w(x,y)};if (w[x][y] < INF && d[x] < INF && d[y] > d[x] + w[x][y])  //这里我加入了w[][]和d[]无穷大,防止后面的相加溢出。                        { d[y] = d[x] + w[x][y];}}}int main(){cin >> N >> C >> S >> T;for (int i = 1; i <= N; ++i) {   // 初始化所有点不连通for (int j = 1; j <= N; ++j) {w[i][j] = INF;}}int u, v, c;for (int i = 0; i < C; ++i) {cin >> u >> v >> c;if (c < w[u][v]) w[u][v] = w[v][u] = c;  //由于是无向图,所以要求设置 u->v 和 v->u都有边。}dij(S);        cout << d[T] << endl;return 0;}

如果还有不懂,可以问我。

如果有错,希望指出。

谢谢大家。

0 0