1003 Emergency (25 分)

  • 题意 :求无向图中最短路的数量,以及在最短路情况下,点权之和最大是多少
  • 思路 :dijkstra的扩展一般在第三步“用t更新其它点“;spfa不能用来求最短路的数量(因为每个点可能被更新多次);假设有三个点可以走到终点x,那么从起点s走到x的路径分为三类,s->1->x…,如果d1<d2<d3,最短距离的数量就是走到第一个点的数量,如果d1=d2<d3,前两个相加,同理,求最短路情况下点权和最大,就是三者取max(如果三者相同);cnt数组记录从起点走到i的最短路径数量;sum数组记录从起点到i的最大点权
  • 语法 :如果点数<=1000,邻接矩阵就没有问题,>=1e4就一定要邻接表存;
#include <iostream>
#include <cstring>using namespace std;const int N = 510;int n, m, S, T;
int w[N], g[N][N];
int cnt[N], sum[N];
int dist[N];
bool st[N];void dijkstra()
{memset(dist, 0x3f, sizeof dist);       // 初始化dist[S] = 0, cnt[S] = 1, sum[S] = w[S];for (int i = 0; i < n - 1; i ++ ){int t = -1;for (int j = 0; j < n; j ++ )if (!st[j] && (t == -1 || dist[t] > dist[j]))t = j;st[t] = true;      // 标记for (int j = 0; j < n; j ++ )if (dist[j] > dist[t] + g[t][j]){dist[j] = dist[t] + g[t][j];cnt[j] = cnt[t];sum[j] = sum[t] + w[j];}else if (dist[j] == dist[t] + g[t][j]){cnt[j] += cnt[t];sum[j] = max(sum[j], sum[t] + w[j]);}}
}int main()
{cin >> n >> m >> S >> T;for (int i = 0; i < n; i ++ ) cin >> w[i];memset(g, 0x3f, sizeof g);       // 初始化while (m -- ){int a, b, c;cin >> a >> b >> c;g[a][b] = g[b][a] = min(g[a][b], c);     // 无向图}dijkstra();cout << cnt[T] << ' ' << sum[T];return 0;
}
  • 思路 :dijkstra中在循环for或者while的外面初始化时,起点的st不要设成true!堆优化版在一个点被更新松弛后将它放入优先队列内
  • 语法 :堆优化版写成链式前向星,M开成N*N
// 堆优化版
#include <iostream>
#include <cstring>
#include <queue>using namespace std;const int N = 510, M = N * N;       // 注意M大小typedef pair<int, int> pii;int h[N], w[M], e[M], ne[M], idx;
int wt[N];
int dist[N];
bool st[N];
int cnt[N], sum[N];
int n, m, S, T;void add(int a, int b, int c)
{e[idx] = b, w[idx] = c, ne[idx] = h[a], h[a] = idx ++ ;
}void dijkstra()
{memset(dist, 0x3f, sizeof dist);dist[S] = 0;cnt[S] = 1, sum[S] = wt[S];priority_queue<pii, vector<pii>, greater<pii>> heap;heap.push({0, S});//    st[S] = true;         注意!!!while (heap.size()){auto t = heap.top();heap.pop();int ver = t.second, distance = t.first;if (st[ver]) continue;st[ver] = true;for (int i = h[ver]; i != -1; i = ne[i]){int j = e[i];if (dist[j] > dist[ver] + w[i]){dist[j] = dist[ver] + w[i];cnt[j] = cnt[ver];sum[j] = sum[ver] + wt[j];heap.push({dist[j], j});        // 被更新松弛了的点要放入优先队列内}else if (dist[j] == dist[ver] + w[i]){cnt[j] += cnt[ver];sum[j] = max(sum[j], sum[ver] + wt[j]);}}}
}int main()
{memset(h, -1, sizeof h);cin >> n >> m >> S >> T;for (int i = 0; i < n; i ++ ) cin >> wt[i];while (m -- ){int a, b, c;cin >> a >> b >> c;add(a, b, c);add(b, a, c);}dijkstra();cout << cnt[T] << ' ' << sum[T];return 0;
}

1018 Public Bike Management (30 分)

题意 :

  • 给一个终点,要从起点出发,要找到一条路径,第一优先级的要求是 距离最短;如果有很多条距离相同的路径,第二优先级,最初带去的自行车数量越少越好;第三优先级,最终带回的自行车数量越少越好

思路 :

  • 多关键字的dijk,但前面的问题是可以在dijk过程中去满足,这题比较特殊,后面两个要求是不能再dijk过程中去满足的;比如从两个点中选一个去第三个点,第一个点出发要带5辆车,第二个点出发要带6辆车,但我们无法分析到底哪个点更好,比如到第三个点恰好缺5辆,第一个点就更好,但也有可能缺6辆,第二个点就更好。像以前的关键字都是累加的,第一关键字距离第二关键字时间,时间肯定越短越好,但这题无法判断
  • 所以这题就比较复杂,先做一遍dijk,求每个点终点的最短距离,然后再去把所有从起点到终点的最短距离搜索一遍,从所有的最短路径中找后两个条件最好的
  • 这题本应是指数级复杂度,但对于一个随机图而言,最短路径不会太多
  • 求dijk是为了剪枝,保证走的时候是最短路径;比如我们当前在u点,要判断u点走到v点有没有可能使是最短路径呢?可以用dist数组判断,如果dist[u] = dist[u -> v] + dist[v],那么说明我们搜的时候可以从u走到v,这其实就是一个剪枝
  • 用一个变量s表示当前需要带去多少自行车,可以是负数,在过程中,负数的最小值就是我们需要带去的自行车;带回的自行车是多少呢?就是看最终s的值是多少,再加上带去的数量
  • 爆搜时用一个vector容器 的 path来存路径,ans来存答案路径
  • 当爆搜到终点时,在计算需要带的数量sd时,此时的mins有可能为正数,也就是一辆都不用带,所以要和0取最小的,最终需要带走的数量bg就是s加上sd
  • 注意这个mins不是全局变量!!是当前这条路径上的最小值
  • dfs时,假设放了,之后还要回溯pop_back

语法 :

  • s -= (C + 1) / 2 - c[u];是上取整
  • 带权无向图,首先初始化g数组为无穷;带权,未说明是否有重边,因此取min
  • 初始时,dfs前,不要忘了往里面加上起点0
#include <iostream>
#include <vector>
#include <cstring>
using namespace std;#define pb push_backconst int N = 510, INF = 0x3f3f3f3f;int C, n, S, m;
int c[N];
int g[N][N];
int dist[N];
bool st[N];vector<int> path, ans;int send = INF, bring = INF;void dijkstra()
{memset(dist, 0x3f, sizeof dist);dist[S] = 0;for (int i = 0; i < n; i ++ ){int t = -1;for (int j = 0; j <= n; j ++ )if (!st[j] && (t == -1 || dist[t] > dist[j]))t = j;st[t] = true;for (int j = 0; j <= n; j ++ )dist[j] = min(dist[j], dist[t] + g[t][j]);}
}void dfs(int u, int s, int mins)
{if (u){s -= (C + 1) / 2 - c[u];mins = min(mins, s);}if (u == S){int sd = abs(min(0, mins));int bg = sd + s;if (sd < send || (sd == send && bring > bg))ans = path, send = sd, bring = bg;return ;}for (int i = 1; i <= n; i ++ )if (dist[u] == dist[i] + g[u][i]){path.pb(i);dfs(i, s, mins);path.pop_back();}
}int main()
{scanf("%d%d%d%d", &C, &n, &S, &m);for (int i = 1; i <= n && scanf("%d", &c[i]); i ++ );memset(g, 0x3f, sizeof g);for (int i = 0, x, y, z; i < m && scanf("%d%d%d", &x, &y, &z); i ++ )g[x][y] = g[y][x] = min(g[x][y], z);dijkstra();path.pb(0);dfs(0, 0, 0);printf("%d 0", send);for (int i = 1; i < ans.size(); i ++ ) printf("->%d", ans[i]);printf(" %d", bring);
}

1122 Hamiltonian Cycle (25 分)

题意 :

  • Hamiltonian Cycle哈密顿回路
  • 哈密顿回路问题是找到一个包含图中每个顶点的简单回路。
  • 在本题中,你需要做的是判断给定路径是否为哈密顿回路。
  • 无向图

思路 :

  • 恰好每个点走一次,且第一个点和最后一个点是同一个点
  • 如果满足了以上两个要求,就按它给的路径走一遍,如果从当前这个点都能走到下一个点,且所有点都走了一次,就是哈密顿路径
  • 这题有一个很坑的地方,题目只说了图中点的数量是200,但没说输入的路径的点数也是200,所以如果路径数组开太小,会有一个点过不了
#include <iostream>
using namespace std;const int N = 210;int n, m;
int nodes[N * 2], cnt;
bool g[N][N];
bool st[N];bool check()
{if (cnt != n + 1 || nodes[0] != nodes[cnt - 1]) return false;for (int i = 1; i <= n; i ++ ) st[i] = 0;for (int i = 0; i < cnt - 1; i ++ ){st[nodes[i]] = true;if (!g[nodes[i]][nodes[i + 1]])return false;}for (int i = 1; i <= n; i ++ )if (!st[i])return false;return true;
}int main()
{scanf("%d%d", &n, &m);int a, b;while (m -- ){scanf("%d%d", &a, &b);g[a][b] = g[b][a] = true;}int k; scanf("%d", &k);while (k -- ){scanf("%d", &cnt);for (int i = 0; i < cnt; i ++ ) scanf("%d", &nodes[i]);if (check()) puts("YES");else puts("NO");}
}

1126 Eulerian Path (25 分)

题意 :

  • Eulerian Path欧拉路径
  • circuit环路;degree度数
  • 欧拉路径是图中的一条路径,该路径满足恰好访问每个边一次。
  • 欧拉回路是一条在同一顶点处开始和结束的欧拉路径。
  • 如果一个连通图的所有顶点的度数都为偶数,那么这个连通图具有欧拉回路,且这个图被称为欧拉图
  • 如果一个连通图中有两个顶点的度数为奇数,其他顶点的度数为偶数,那么所有欧拉路径都从其中一个度数为奇数的顶点开始,并在另一个度数为奇数的顶点结束。
  • 具有欧拉路径但不具有欧拉回路的图被称为半欧拉图
  • 现在,给定一个无向图,请你判断它是欧拉图、半欧拉图还是非欧拉图。

思路 :

  • 每个点的度数是什么呢?就是这个点连的边数
  • 首先不管是欧拉图还是半欧拉图都必须是连通的;所以第一步是判断连通性,从某个点出发,看能否把所有点搜到,dfs或者bfs;这个判断连通性是 图的遍历,时间复杂度为 点数加边数
  • 然后判断度数,直接按照定义即可
  • 判断连通性的写法 :从1号点出发,看能搜到几个点,遍历的时候为了避免重复搜索,要有一个判重数组
#include <iostream>
using namespace std;const int N = 510;int n, m;
bool g[N][N];
int d[N];
bool st[N];     // dfs用int dfs(int u)
{st[u] = true;int cnt = 1;for (int i = 1; i <= n; i ++ ){if (!st[i] && g[u][i])cnt += dfs(i);}return cnt;
}int main()
{scanf("%d%d", &n, &m);int a, b;while (m -- ){scanf("%d%d", &a, &b);g[a][b] = g[b][a] = true;d[a] ++ , d[b] ++ ;}int cnt = dfs(1);printf("%d", d[1]);for (int i = 2; i <= n; i ++ ) printf(" %d", d[i]);puts("");if (cnt == n){int s = 0;for (int i = 1; i <= n; i ++ )if (d[i] % 2)s ++ ;if (!s) puts("Eulerian");else if (s == 2) puts("Semi-Eulerian");else puts("Non-Eulerian");}elseputs("Non-Eulerian");
}

1134 Vertex Cover (25 分)

题意 :

  • 如果图中的一个顶点集合能够满足图中的每一条边都至少有一个端点在该集合内,那么这个顶点集合就是图的顶点覆盖。
  • 现在给定一张图,以及若干个顶点集合,请你判断这些顶点集合是否是图的顶点覆盖。

思路 :

  • 直接模拟即可
#include <iostream>
#include <cstring>using namespace std;const int N = 10010;int n, m;
struct Edge
{int a, b;
}e[N];
bool st[N];int main()
{cin >> n >> m;for (int i = 0; i < m; i ++ ) cin >> e[i].a >> e[i].b;int k;cin >> k;while (k -- ){int cnt;cin >> cnt;memset(st, 0, sizeof st);while (cnt -- ){int x;cin >> x;st[x] = true;}int i;for (i = 0; i < m; i ++ )if (!st[e[i].a] && !st[e[i].b])break;if (i == m) puts("Yes");else puts("No");}return 0;
}

1142 Maximal Clique (25 分)

题意 :

  • 在一个无向图中,如果一个顶点子集满足子集内的任意两个不同顶点之间都是相连的,那么这个顶点子集就被称为一个团。
  • 如果一个团不能通过加入某个新的顶点来扩展成一个更大的团,那么该团就被称为最大团。
  • 现在,你需要判断给定顶点子集能否构成一个最大团。
#include <iostream>
#include <cstring>
using namespace std;const int N = 210;int n, m;
bool g[N][N];
int nodes[N], cnt;
bool st[N];bool check_clique()
{for (int i = 0; i < cnt; i ++ )for (int j = 0; j < i; j ++ )if (!g[nodes[i]][nodes[j]])return false;return true;
}bool check_maximum()
{memset(st, 0, sizeof st);for (int i = 0; i < cnt; i ++ )st[nodes[i]] = true;for (int i = 1; i <= n; i ++ ){if (!st[i]){bool success = false;for (int j = 0; j < cnt; j ++ )if (!g[i][nodes[j]]){success = true;break;}if (!success) return false;}}return true;
}int main()
{scanf("%d%d", &n, &m);int a, b;while (m -- ){scanf("%d%d", &a, &b);g[a][b] = g[b][a] = true;}int k; scanf("%d", &k);while (k -- ){scanf("%d", &cnt);for (int i = 0; i < cnt; i ++ ) scanf("%d", &nodes[i]);if (check_clique()){if (check_maximum()) puts("Yes");else puts("Not Maximal");}elseputs("Not a Clique");}
}

1146 Topological Order (25 分)

题意 :

  • 以下哪个选项不是从给定的有向图中获得的拓扑序列?
  • 现在,请你编写一个程序来测试每个选项。

思路 :

  • 将输入的每一条边存下来
  • 对于每对询问,遍历每条边,如果边的起点比边的终点在询问中出现的位置晚,说明询问不合格

语法 :

  • is_first的使用,如果是true,将其转为false;否则输出空格
#include <iostream>
#include <cstring>using namespace std;const int N = 1010, M = 10010;int n, m;
struct Edge
{int a, b;
}e[M];
int p[N];int main()
{cin >> n >> m;for (int i = 0; i < m; i ++ ) cin >> e[i].a >> e[i].b;int k;cin >> k;bool is_first = true;for (int i = 0; i < k; i ++ ){for (int j = 1; j <= n; j ++ ){int x;cin >> x;p[x] = j;}bool success = true;for (int j = 0; j < m; j ++ )if (p[e[j].a] > p[e[j].b]){success = false;break;}if (!success){if (is_first) is_first = false;else cout << ' ';cout << i;}}cout << endl;return 0;
}

1150 Travelling Salesman Problem (25 分)

思路 :

  • 如果所给的路径中不连通,success为false,sum为-1,输出NA;如果第一个点和最后一个不是同一个点,没有遍历所有点;遍历完路径后,如果有点没有被路径包含,则success为false,输出不是一个访问了所有城市的回路;
  • 如果路径点的数量等于n+1,说明是简单回路,否则就不是简单回路
  • 然后动态维护最小距离和最小距离的组号
  • 无向带权图,因此初始化距离为正无穷
  • 用sum表示路径和,如果是-1,说明无法计算;success表示是否是否访问了所有城市
#include <iostream>
#include <cstring>using namespace std;const int N = 210, INF = 0x3f3f3f3f;int n, m;
int d[N][N], vers[310];
bool st[N];int main()
{cin >> n >> m;memset(d, 0x3f, sizeof d);for (int i = 0; i < m; i ++ ){int a, b, c;cin >> a >> b >> c;d[a][b] = d[b][a] = c;}int k;cin >> k;int min_dist = INF, min_id;for (int T = 1; T <= k; T ++ ){int cnt;cin >> cnt;for (int i = 0; i < cnt; i ++ ) cin >> vers[i];int sum = 0;bool success = true;memset(st, 0, sizeof st);for (int i = 0; i + 1 < cnt; i ++ ){int a = vers[i], b = vers[i + 1];if (d[a][b] == INF){sum = -1;success = false;break;}else sum += d[a][b];st[a] = true;}for (int i = 1; i <= n; i ++ )if (!st[i]){success = false;break;}if (vers[0] != vers[cnt - 1]) success = false;if (sum == -1) printf("Path %d: NA (Not a TS cycle)\n", T);else{if (!success) printf("Path %d: %d (Not a TS cycle)\n", T, sum);else{if (cnt == n + 1) printf("Path %d: %d (TS simple cycle)\n", T, sum);else printf("Path %d: %d (TS cycle)\n", T, sum);if (min_dist > sum){min_dist = sum;min_id = T;}}}}printf("Shortest Dist(%d) = %d\n", min_id, min_dist);return 0;
}

1154 Vertex Coloring (25 分)

题意 :

  • 一个合适的顶点着色是指用各种颜色标记图中各个顶点,使得每条边的两个端点的颜色都不相同。
  • 如果一种合适的顶点着色方案使用了一共 k 种不同的颜色,则称其为合适的 k 着色(k-coloring)。
  • 现在,你需要判断给定的着色方案是否是合适的 k 着色方案。

思路 :

  • 用结构体存边
  • 对于每一个询问,首先遍历所有边,如果所有边的颜色都没有出现矛盾,再判断颜色数量是否是k种
#include <iostream>
#include <cstring>
#include <unordered_set>using namespace std;const int N = 10010;int n, m;
struct Edge
{int a, b;
}e[N];
int color[N];int main()
{cin >> n >> m;for (int i = 0; i < m; i ++ ) cin >> e[i].a >> e[i].b;int k;cin >> k;while (k -- ){for (int i = 0; i < n; i ++ ) cin >> color[i];bool success = true;for (int i = 0; i < m; i ++ )if (color[e[i].a] == color[e[i].b]){success = false;break;}if (success){unordered_set<int> S;for (int i = 0; i < n; i ++ ) S.insert(color[i]);printf("%d-coloring\n", S.size());}else puts("No");}return 0;
}

PAT甲级题目翻译+答案 AcWing(图论)相关推荐

  1. PAT甲级题目翻译+答案 AcWing(数学)

    1059 Prime Factors (25 分) 题意 : 给一正整数,要求分解质因数 思路 : 使用is_first,来完成除了第一个质因数前都有*的效果 如果n=1,要特判 最后如果n>1 ...

  2. PAT甲级题目翻译+答案 AcWing(排序)

    1012 The Best Rank (25 分) 题意 :给ID和3门成绩,计算其平均分A,输出每位学生最好的排名,A>C>M>E 思路 :如果将所需的若干个元素中使第一个元素为后 ...

  3. PAT甲级题目翻译+答案 AcWing(模拟)

    1008 Elevator (20 分) 思路 :last可能等于cur,而无论是否相等,res都是+5的 #include <iostream>using namespace std;i ...

  4. PAT甲级题目翻译+答案 AcWing(动态规划)

    1007 Maximum Subsequence Sum (25 分) 题意 :注意最后输出的不是索引而是在那个索引的数 思路 :f为当前的假设开始指针,每一次累加到sum,如果sum大于res,就更 ...

  5. PAT甲级题目翻译+答案 AcWing(进位制)

    1010 Radix (25 分) 题意 :radix进制 题意 :给两个数和其中一个数的进制,问另一个数能否在某一进制下与这数相等 思路 :如果tag等于2就交换,最后还是只需要处理tag为1这种情 ...

  6. PAT甲级题目翻译+答案 AcWing(字符串处理)

    1001 A+B Format (20 分) 题意 :将整数转换成标准格式 思路 :从后往前遍历字符串进行模拟,每三个数字加一个逗号,但不能是在最前面加逗号,也不能是加在负号后面 #include & ...

  7. PAT甲级题目翻译+答案 AcWing(贪心)

    1033 To Fill or Not to Fill (25 分) 题意 : 坐标轴上有n个加油站,给出每个加油站的位置和油价格,给出总路程长度和油箱最大容量,以及每升油平均跑多少路,最开始油箱是空 ...

  8. PAT甲级题目翻译+答案 AcWing(链表)

    1032 Sharing (25 分) 题意 : suffix后缀:prefix前缀 每个结点存一个字母,一共存两个单词 分别给两个单词的第一个字母的地址以及总共的结点数 给出所有结点的地址数值和下一 ...

  9. PAT甲级题目翻译+答案 AcWing(树)

    1004 Counting Leaves (30 分) 题意 : 家庭关系可以用家谱树来表示,给定一个家谱树,你的任务是找出其中没有孩子的成员. 第一行包含一个整数 N 表示树中结点总数以及一个整数 ...

最新文章

  1. P4491 [HAOI2018]染色
  2. 对传入的值,转成整数
  3. tf.clip_norm
  4. 蓝牙耳机和蓝牙鼠标相互干扰_TWS蓝牙耳机哪个牌子好?主流无线蓝牙耳机推荐...
  5. Mysql -uroot -p 登陆不上_MySQL命令行登陆,远程登陆MySQL 的方法
  6. VTK:图片之PickPixel2
  7. 自然语言处理hanlp的入门基础
  8. Elastic Stack 安装
  9. c语言贪吃蛇(简易版本含完整代码)
  10. uv422转换为yuv420_利用libswscale转换yuyv422到yuv422p或rgb之间的转换, 视频翻转
  11. 用php制作一个简单的网页留言板
  12. 【简历】Android简历该这样写
  13. 美团成都一面面经及详细答案
  14. ECharts中Y轴坐标上标记有实心圆
  15. android读取剪切板的方法,Android获取粘贴板内容
  16. 怎么给手机照片添加文字?没想到方法这么容易,1分钟就能学会
  17. 你见过出身最奇特的程序员是什么样的?
  18. 1.5. 唤醒任务:TTWU(try_to_wake_up)
  19. 游戏鼠标的dpi测试软件,高DPI无用?一分钟测试你所需的鼠标DPI
  20. java zhs16gbk_JAVA-----乱码的处理 乱码的解决方法总结

热门文章

  1. [面向对象] ABAP中类重构助手Refactoring Assitant
  2. 采购订单单位与基本计量单位不一致问题案例
  3. BASISI系统中如何配置web service
  4. 解决SAP中单位转换问题
  5. SAP SD 定价过程的16个字段的作用说明
  6. update module
  7. 海外净利润低?海尔智家H股上市有望看齐国内!
  8. 频频转型的蘑菇街,能讲好直播这个“老故事”吗?
  9. 如何用计算机加出5281314,电脑每次开机进入桌面后都黑屏两次,然后就好了,什么情况?怎么处理...
  10. java word分词器使用_word分词器使用(java)