From ce2b06bf1edcba2783919f1f822c645c3d7a6a28 Mon Sep 17 00:00:00 2001 From: e2hang <2099307493@qq.com> Date: Mon, 8 Dec 2025 22:54:52 +0800 Subject: [PATCH] New Exercise --- Exercise/Homework7/Q1KahTuoPu.cpp | 51 +++++++++ Exercise/Homework7/Q2KahTuoPuAOE.cpp | 86 +++++++++++++++ Exercise/Homework7/Q3Dij.cpp | 71 ++++++++++++ Exercise/Homework7/readme.md | 116 ++++++++++++++++++++ Exercise/Homework8/Q1Dij.cpp | 58 ++++++++++ Exercise/Homework8/Q2dpMul.cpp | 120 ++++++++++++++++++++ Exercise/Homework8/Q3MiniTree.cpp | 67 ++++++++++++ Exercise/Homework8/readme.md | 157 +++++++++++++++++++++++++++ 8 files changed, 726 insertions(+) create mode 100644 Exercise/Homework7/Q1KahTuoPu.cpp create mode 100644 Exercise/Homework7/Q2KahTuoPuAOE.cpp create mode 100644 Exercise/Homework7/Q3Dij.cpp create mode 100644 Exercise/Homework7/readme.md create mode 100644 Exercise/Homework8/Q1Dij.cpp create mode 100644 Exercise/Homework8/Q2dpMul.cpp create mode 100644 Exercise/Homework8/Q3MiniTree.cpp create mode 100644 Exercise/Homework8/readme.md diff --git a/Exercise/Homework7/Q1KahTuoPu.cpp b/Exercise/Homework7/Q1KahTuoPu.cpp new file mode 100644 index 0000000..72c9aaa --- /dev/null +++ b/Exercise/Homework7/Q1KahTuoPu.cpp @@ -0,0 +1,51 @@ +#include +#include +#include + +using namespace std; + +int main(){ + int n, m; + cin >> n >> m; + vector> adj(n); + vector degree(n, 0); + + for(int i = 0; i < m; i++){ + int u, v; + cin >> u >> v; + adj[u].push_back(v); + degree[v]++; + } + + priority_queue, greater> pq; + + for(int i = 0; i < n; i++){ + if(degree[i] == 0){ + pq.push(i); + } + } + vector ans; + + while(!pq.empty()){ + int u = pq.top(); + pq.pop(); + ans.push_back(u); + for(int v : adj[u]){ + degree[v]--; + if(degree[v] == 0){ + pq.push(v); + } + } + } + + if(ans.size() != n){ + cout << "unworkable project" << endl; + }else{ + for(int i = 0; i < n; i++){ + cout << ans[i] << " "; + } + cout << endl; + } + + return 0; +} \ No newline at end of file diff --git a/Exercise/Homework7/Q2KahTuoPuAOE.cpp b/Exercise/Homework7/Q2KahTuoPuAOE.cpp new file mode 100644 index 0000000..982ae25 --- /dev/null +++ b/Exercise/Homework7/Q2KahTuoPuAOE.cpp @@ -0,0 +1,86 @@ +#include +#include +#include +#include + +using namespace std; + +int main(){ + int n, m; + while(cin >> n >> m) { + vector>> adj(n + 1); + vector degree(n + 1, 0); + vector, int>> edges; + queue q; + vector topo; + vector ve(n + 1, 0); + for(int i = 0; i < m; i++) { + int a, b, w; + cin >> a >> b >> w; + a--; b--; + adj[a].push_back(make_pair(b, w)); + degree[b]++; + edges.push_back(make_pair(make_pair(a, b), w)); + } + for(int i = 0; i < n; i++) { + if(degree[i] == 0) { + q.push(i); + } + } + while(!q.empty()) { + int u = q.front(); + q.pop(); + topo.push_back(u); + for(auto [v, w] : adj[u]) { + degree[v]--; + if(degree[v] == 0) { + q.push(v); + } + } + } + //topo为拓扑排序 + if(topo.size() != n) { + cout << "unworkable project" << endl; + continue; + } + //正向一次,求出最早开始时间 + for(int i = 0; i < topo.size(); i++) { + int u = topo[i]; + for(auto [v, w] : adj[u]) { + ve[v] = max(ve[v], ve[u] + w); + } + } + int max_ve = 0; + for(int i = 0; i < n; i++) { + max_ve = max(max_ve, ve[i]); + } + //反向一次,求出最晚开始时间 + vector vl(n + 1, max_ve); + for(int i = topo.size() - 1; i >= 0; i--) { + int u = topo[i]; + for(auto [v, w] : adj[u]) { + vl[u] = min(vl[u], vl[v] - w); + } + } + + cout << max_ve << endl; + + //判断是否关键路径 + vector> is_critical; + for(auto e : edges) { + int a = e.first.first; + int b = e.first.second; + int w = e.second; + if(ve[a] + w == vl[b]) { + is_critical.push_back(make_pair(a, b)); + } + } + sort(is_critical.begin(), is_critical.end()); + for(auto [a, b] : is_critical) { + a++; b++; + cout << a << "->" << b << endl; + } + } + + return 0; +} \ No newline at end of file diff --git a/Exercise/Homework7/Q3Dij.cpp b/Exercise/Homework7/Q3Dij.cpp new file mode 100644 index 0000000..dd4fadb --- /dev/null +++ b/Exercise/Homework7/Q3Dij.cpp @@ -0,0 +1,71 @@ +#include +#include +#include + +using namespace std; +const int INF = 1e9; +vector>> adj; +vector dist; +vector vis; +vector> path; +priority_queue, vector>, greater>> pq; +bool lessthan(vector a, vector b) { + for(int i = 0; i < min(a.size(), b.size()); i++) { + if(a[i] < b[i]) return true; + if(a[i] > b[i]) return false; + } + return a.size() < b.size(); +} + +int main() { + int n, m; + cin >> n >> m; + adj.resize(n + 1); + dist.resize(n + 1, INF); + vis.resize(n + 1, false); + path.resize(n + 1); + for(int i = 0; i < m; i++) { + int a, b, c; + cin >> a >> b >> c; + adj[a].push_back(make_pair(b, c)); + } + + dist[0] = 0; + path[0].push_back(0); + pq.push(make_pair(0, 0)); + while(!pq.empty()) { + int u = pq.top().second; + pq.pop(); + if(vis[u]) continue; + vis[u] = true; + for(auto [v, w] : adj[u]) { + if(dist[v] > dist[u] + w) { + dist[v] = dist[u] + w; + path[v] = path[u]; + path[v].push_back(v); + pq.push(make_pair(dist[v], v)); + } + else if(dist[v] == dist[u] + w) { + vector new_path = path[u]; + new_path.push_back(v); + if(path[v].empty() || path[v].size() > new_path.size() || + (path[v].size() == new_path.size() && lessthan(new_path, path[v]))) { + path[v] = new_path; + pq.push(make_pair(dist[v], v)); + } + } + } + } + + for(int i = 1; i < n; i++) { + if(dist[i] != INF && !path[i].empty()) { + for(int j = 0; j < path[i].size(); j++) { + if(j > 0) cout << "->"; + cout << path[i][j]; + } + cout << endl; + } + } + + return 0; +} \ No newline at end of file diff --git a/Exercise/Homework7/readme.md b/Exercise/Homework7/readme.md new file mode 100644 index 0000000..c595cb1 --- /dev/null +++ b/Exercise/Homework7/readme.md @@ -0,0 +1,116 @@ +``` cpp + +A 任务排序 +分数 30 +作者 朱允刚 +单位 吉林大学 +一个工程被分解成n个子任务,编号为0至n-1。要完成整个工程需要完成所有的子任务。其中一些子任务必须先于另外一些子任务被完成。给定各子任务之间的先后关系,请编写程序给出一个合理的任务完成顺序,若工程不可行,程序亦能识别。 + +输入格式: +输入第一行为两个整数n和e,均不超过100。n表示子任务数。接下来e行,表示已知的两个子任务间的先后关系,每行为两个整数a和b,表示任务a必须先于任务b完成。 + +输出格式: +若工程不可行(一些子任务以自己为先决条件),输出“unworkable project”;若工程可行,输出为1行整数,每个整数后一个空格,为n个子任务的编号,表示子任务的完成顺序,如果有多种可能的顺序,则输出字典序最小者。 + +注:字典序,即对象在字典中的顺序。对于两个数字序列,从第一个数字开始比较,当某一个位置的数字不同时,该位置数字较小的序列,字典序较小,例如1 2 3 9比1 2 4 5小,1 2 8 9比1 2 10 3小。 + +输入样例1: +3 2 +0 1 +1 2 +输出样例1: +0 1 2 +输入样例2: +3 3 +0 1 +1 2 +2 0 +输出样例2: +unworkable project +代码长度限制 +16 KB +时间限制 +50 ms +内存限制 +64 MB +栈限制 +8192 KB + +--- + +B 关键路径 +分数 30 +作者 朱允刚 +单位 吉林大学 +假定一个工程由若干子任务构成,使用一个包含n个顶点、e条边的AOE网表示该工程,顶点编号为1至n,有向边表示该工程的每个子任务,边的权值表示完成该子任务所需的时间,假定网中只含一个源点和一个汇点。请编写程序求出该工程的所有关键活动,并计算完成该工程所需的最短时间。 + +输入格式: +每个测试点包含多组测试数据。每组数据第一行为2个整数n和e,均不超过200,分别表示AOE网的顶点数和边数。接下来e行表示每条边的信息,每行为3个正整数a、b、c,其中a和b表示该边的端点编号,c表示权值。各边并不一定按端点编号顺序排列,且各顶点并不一定按拓扑序排列。 + +输出格式: +对每组数据,若工程不可行(AOE网中存在环),输出“unworkable project”;若工程可行,则输出第一行为完成工程所需的最短时间,并从第2行开始输出关键活动,每个关键活动占一行,格式为i->j,其中i和j表示关键活动所在边的端点编号。各关键活动输出顺序为:按i的递增顺序输出,若多个关键活动的i值相同,则按j的递增顺序输出。 + +输入样例: +4 4 +1 2 6 +1 3 4 +2 4 1 +3 4 1 + +输出样例: +7 +1->2 +2->4 + +代码长度限制 +16 KB +时间限制 +100 ms +内存限制 +64 MB +栈限制 +8192 KB + +--- + +C 最少点字典序最短路径 +分数 40 +作者 朱允刚 +单位 吉林大学 +给定一个正权有向图,图中包含n个顶点,编号为0至n-1。以顶点0作为源点,请编写程序求顶点0到各顶点的最短路径。若顶点0到某顶点存在多条最短路径,则输出经过顶点最少的那条路径,例如图1(a)中0到4的经过顶点最少的最短路径为0 - 3 - 4。若存在多条最短路径且其经过顶点个数相等,则输出字典序最小者。例如图1(b)中0到5的满足条件的最短路径为0 - 2 - 5。 + +g.jpg + +注:字典序,即对象在字典中的顺序。对于两个数字序列,从第一个数字开始比较,当某一个位置的数字不同时,该位置数字较小的序列,字典序较小,例如1 2 3 9比1 2 4 5小,1 2 8 9比1 2 10 3小。 + +输入格式: +输入第一行为两个正整数n和e,分别表示图的顶点数和边数,其中n不超过20000,e不超过20000。接下来e行表示每条边的信息,每行为3个非负整数a、b、c,其中a和b表示该边的端点编号,c表示权值。各边并非按端点编号顺序排列。 + +输出格式: +输出为若干行由“->”间隔的数字序列,每行为源点0到某顶点的满足条件的最短路径,如源点到某顶点无最短路径,则不输出该条路径。各条路径按终点的递增顺序输出,源点到源点的最短路径无需输出。 + +输入样例: +6 7 +0 1 1 +1 4 2 +4 5 3 +0 3 4 +3 5 2 +0 2 5 +2 5 1 + +输出样例: +0->1 +0->2 +0->3 +0->1->4 +0->2->5 + +代码长度限制 +16 KB +时间限制 +500 ms +内存限制 +20 MB +栈限制 +8192 KB \ No newline at end of file diff --git a/Exercise/Homework8/Q1Dij.cpp b/Exercise/Homework8/Q1Dij.cpp new file mode 100644 index 0000000..43380a7 --- /dev/null +++ b/Exercise/Homework8/Q1Dij.cpp @@ -0,0 +1,58 @@ +#include +#include +#include + +using namespace std; +const int INF = 1e9; + +int main(){ + int n, e; + while(cin >> n >> e){ + //直接dp解决 + vector> dp(n, vector(n, INF)); + + for(int i = 0; i < n; i++){ + dp[i][i] = 0; + } + + for(int i = 0; i < e; i++){ + int a, b, c; + cin >> a >> b >> c; + dp[a][b] = min(dp[a][b], c); + dp[b][a] = min(dp[b][a], c); + } + + for(int k = 0; k < n; k++){ + for(int i = 0; i < n; i++){ + for(int j = 0; j < n; j++){ + if(dp[i][k] != INF && dp[k][j] != INF){ + dp[i][j] = min(dp[i][j], dp[i][k] + dp[k][j]); + } + } + } + } + + int mins = INF; + int out = 0; + for(int i = 0; i < n; i++){ + int sum = 0; + bool valid = true; + for(int j = 0; j < n; j++){ + if(dp[i][j] == INF){ + valid = false; + break; + } + sum += dp[i][j]; + } + + if(valid && sum < mins){ + mins = sum; + out = i; + } + } + + cout << out << endl; + } + + return 0; +} \ No newline at end of file diff --git a/Exercise/Homework8/Q2dpMul.cpp b/Exercise/Homework8/Q2dpMul.cpp new file mode 100644 index 0000000..28b1803 --- /dev/null +++ b/Exercise/Homework8/Q2dpMul.cpp @@ -0,0 +1,120 @@ +#include +#include +#include +#include +#include +using namespace std; + +const int INF = INT_MAX; + +struct Edge { + int to; + int time; + Edge(int t, int w) : to(t), time(w) {} +}; + +struct Node { + int station; + int state; //0没用过,1用过了 + int time; + + Node(int s, int st, int t) : station(s), state(st), time(t) {} + + bool operator>(const Node& other) const { + return time > other.time; + } +}; + +int main() { + int n, s, t; + + while (cin >> n >> s >> t) { + int m; + cin >> m; + vector> bus(n + 1); + for (int i = 0; i < m; i++) { + int a, b, c; + cin >> a >> b >> c; + bus[a].push_back(Edge(b, c)); + bus[b].push_back(Edge(a, c)); + } + + int k; + cin >> k; + vector> metro(n + 1); + for (int i = 0; i < k; i++) { + int x, y, z; + cin >> x >> y >> z; + metro[x].push_back(Edge(y, z)); + metro[y].push_back(Edge(x, z)); + } + vector> dp(n + 1, vector(2, INF)); + + //换乘点K + vector K_record(n + 1, INF); + + priority_queue, greater> pq; + + dp[s][0] = 0; + pq.push(Node(s, 0, 0)); + + while (!pq.empty()) { + Node curr = pq.top(); + pq.pop(); + + int u = curr.station; + int state = curr.state; + int time = curr.time; + + if (time > dp[u][state]) { + continue; + } + + for (const Edge& e : bus[u]) { + int v = e.to; + int new_time = time + e.time; + + if (new_time < dp[v][state]) { + dp[v][state] = new_time; + if (state == 1 && K_record[u] != INF) { + K_record[v] = K_record[u]; + + } + pq.push(Node(v, state, new_time)); + } else if (new_time == dp[v][state] && state == 1 && K_record[u] != INF) { + if (K_record[v] == INF) { + K_record[v] = K_record[u]; + } else { + K_record[v] = min(K_record[v], K_record[u]); + } + } + } + + if (state == 0) { + for (const Edge& e : metro[u]) { + int v = e.to; + int new_time = time + e.time; + + if (new_time < dp[v][1]) { + dp[v][1] = new_time; + K_record[v] = u; + pq.push(Node(v, 1, new_time)); + } else if (new_time == dp[v][1]) { + K_record[v] = min(K_record[v], u); + } + } + } + } + + int T = min(dp[t][0], dp[t][1]); + cout << T << endl; + + if (dp[t][0] <= dp[t][1]) { + cout << "no metro" << endl; + } else { + cout << K_record[t] << endl; + } + } + + return 0; +} diff --git a/Exercise/Homework8/Q3MiniTree.cpp b/Exercise/Homework8/Q3MiniTree.cpp new file mode 100644 index 0000000..9191fd0 --- /dev/null +++ b/Exercise/Homework8/Q3MiniTree.cpp @@ -0,0 +1,67 @@ +#include +#include +#include +#include + +using namespace std; + +int find(int x, vector& p) { + if(p[x] != x) p[x] = find(p[x], p); + return p[x]; +} + +int main() { + ios::sync_with_stdio(false); + cin.tie(nullptr); + + int n, m; + cin >> n >> m; + int vir = n;//虚拟节点 + n++; + vector> edges; + + vector p(n); + for (int i = 0; i < n - 1; i++) { + cin >> p[i]; + edges.push_back(make_tuple(vir, i, p[i])); + } + + for(int i = 0; i < m; i++){ + int a, b, w; + cin >> a >> b >> w; + edges.push_back(make_tuple(a, b, w)); + } + + auto cmp = [](const tuple& a, const tuple& b) { + return get<2>(a) < get<2>(b); + }; + sort(edges.begin(), edges.end(), cmp); + + + for(int i = 0; i < n; i++) { + p[i] = i; + } + + + + int mins = 0; + int used = 0; + for(int i = 0; i < edges.size(); i++) { + int u = get<0>(edges[i]); + int v = get<1>(edges[i]); + int w = get<2>(edges[i]); + + int pu = find(u, p); + int pv = find(v, p); + if(pu != pv) { + p[pu] = pv; + mins += w; + used++; + if(used == n - 1) break; + } + } + + cout << mins << endl; + + return 0; +} \ No newline at end of file diff --git a/Exercise/Homework8/readme.md b/Exercise/Homework8/readme.md new file mode 100644 index 0000000..c62a71b --- /dev/null +++ b/Exercise/Homework8/readme.md @@ -0,0 +1,157 @@ +``` cpp + +A 双十一 +分数 30 +作者 吉林大学 +单位 吉林大学 +双十一期间,某著名电商平台为应对销售高峰,准备在n个城市中再增加一个自营仓库,其要求是该仓库设在n个城市中的某个城市,且距离其他所有城市的最短距离之和最小。请编写程序帮助该公司找出设立仓库的地点。假定n个城市编号为0至n-1。 + +输入格式: +输入包含多组数据。每组数据第一行为两个正整数n和e,均不超过100。n表示城市数。接下来e行表示两个城市间的距离信息,每行为3个非负整数a、b、c,其中a和b表示两个城市编号,c表示城市间的距离。 + +提示:可使用EOF判断输入结束。 + +输出格式: +输出为一个整数,表示建立仓库的城市编号,如多个城市满足要求,则输出编号最小者。 + +输入样例: +6 5 +0 1 1 +0 2 1 +0 3 1 +0 4 1 +0 5 1 +4 5 +0 1 1 +0 2 5 +1 2 2 +1 3 4 +2 3 1 + +输出样例: +0 +1 + +代码长度限制 +16 KB +时间限制 +50 ms +内存限制 +64 MB +栈限制 +8192 KB + +--- + +B 去火车站 +分数 30 +作者 朱允刚 +单位 吉林大学 +寒假到了,小明准备坐火车回老家,现在他从学校出发去火车站,CC市去火车站有两种方式:轻轨和公交车。小明为了省钱,准备主要以乘坐公交为主。CC市还有一项优惠政策,持学生证可以免费乘坐一站轻轨(但只能乘坐一站)。小明想尽快到达火车站,请编写程序为小明找到一条从学校到火车站最快的路线及换乘轻轨的方案。 + +假设换乘时间忽略不计,公交车与轻轨站点相同,但线路和速度不一定相同,所有线路都是双向的。可以第一站就乘坐轻轨,也可以最后一站乘坐轻轨,也可以在中间某站坐轻轨。如果乘坐轻轨和不乘坐轻轨到达火车站的时间相同,则无需换乘轻轨。最多坐一站轻轨。 + +输入格式: +输入包含多组数据。每组数据第一行为3个整数n、s和t,分别表示车站数(编号为1至n),小明学校所在的站和火车站所在的站。下一行为一个整数m,表示公交车的线路信息,接下来m行,每行为3个正整数a、b、c,表示公交车从a站到b站需要c分钟。下一行为一个整数k,表示轻轨的线路信息,接下来k行,每行为3个正整数x、y、z,表示轻轨从x站到y站需要z分钟。所有整数均不超过20000。 + +输出格式: +对每组数据输出2行。第1行为1个整数T,表示从学校到达火车站的最短时间;第2行为一个整数K,表示在站点K换乘轻轨,若有多个可能的换乘点,则输出编号最小者,如果无需换乘轻轨,则第二行输出“no metro”。 + +输入样例: +4 1 4 +4 +1 2 2 +1 3 3 +2 4 4 +3 4 5 +1 +2 4 3 +4 1 4 +4 +1 2 2 +1 3 3 +2 4 4 +3 4 5 +1 +2 4 3 + +输出样例: +5 +2 +5 +2 + +代码长度限制 +16 KB +时间限制 +1000 ms +内存限制 +20 MB +栈限制 +8192 KB + +--- + +C 网络布线 +分数 40 +作者 朱允刚 +单位 吉林大学 + +亚洲杯赛期间需要保证运动员公寓网络畅通,以使运动员都能正常上网。 + +假定公寓楼内有n个房间,编号为0…n−1,每个房间都需要网络连接。房间 i 有网络,当且仅当满足如下2个条件之一: + +(1)房间 i 安装了路由器(成本为 r +i +​ + >0) + +(2)房间 i 和房间 j 有网线连接且房间 j 有网络(在房间 i 和房间 j 之间布置网线的成本为 f +ij +​ + >0) + +假定你是赛事组委会的网络工程师,请编写程序设计一个网络布线方案(哪些房间安装路由器,哪些房间之间布置网线),使得所有房间都有网络,且总成本最小。 + +例如下图包含7个房间和10个可能的连接,安装路由器的成本为括号内数字,房间之间布置网线的成本为边的权值。其解决方案为右下图,即在房间1和4安装路由器,并进行图中的网线布置。总成本为120。 + +img.png + +输入格式: +输入第一行为两个正整数n和e;n为房间数,不超过600;e为可能的连接数,不超过2×10 +5 + 。接下来一行为n个空格间隔的正整数,第i个整数(i≥0)表示在房间i安装路由器的成本。接下来e行,每行为3个非负整数i、j、f,表示在房间i和房间j之间布置网线的成本为f。 + +输出格式: +输出为一个整数,表示最优网络布线方案的成本。 + +输入样例: +7 10 +60 10 35 55 40 70 70 +0 1 20 +0 4 75 +0 3 45 +1 3 50 +1 2 15 +2 6 5 +5 6 45 +4 5 5 +3 5 25 +3 6 65 + +输出样例: +120 + +提示: +可引入一个虚拟顶点,将该顶点与其他所有顶点用边相连,边权等于那些顶点的权值。进而形成一个新图,对新图求最小支撑树。注意本题顶点编号从0开始。 +image.png +image.png + +代码长度限制 +16 KB +时间限制 +60 ms +内存限制 +64 MB +栈限制 +8192 KB \ No newline at end of file