New Exercise

This commit is contained in:
e2hang
2025-12-08 22:54:52 +08:00
parent 4965074539
commit ce2b06bf1e
8 changed files with 726 additions and 0 deletions

View File

@@ -0,0 +1,51 @@
#include <iostream>
#include <vector>
#include <queue>
using namespace std;
int main(){
int n, m;
cin >> n >> m;
vector<vector<int>> adj(n);
vector<int> 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<int, vector<int>, greater<int>> pq;
for(int i = 0; i < n; i++){
if(degree[i] == 0){
pq.push(i);
}
}
vector<int> 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;
}

View File

@@ -0,0 +1,86 @@
#include <iostream>
#include <vector>
#include <queue>
#include <algorithm>
using namespace std;
int main(){
int n, m;
while(cin >> n >> m) {
vector<vector<pair<int, int>>> adj(n + 1);
vector<int> degree(n + 1, 0);
vector<pair<pair<int, int>, int>> edges;
queue<int> q;
vector<int> topo;
vector<int> 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<int> 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<pair<int, int>> 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;
}

View File

@@ -0,0 +1,71 @@
#include <iostream>
#include <vector>
#include <queue>
using namespace std;
const int INF = 1e9;
vector<vector<pair<int, int>>> adj;
vector<int> dist;
vector<bool> vis;
vector<vector<int>> path;
priority_queue<pair<int, int>, vector<pair<int, int>>, greater<pair<int, int>>> pq;
bool lessthan(vector<int> a, vector<int> 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<int> 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;
}

View File

@@ -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不超过20000e不超过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

View File

@@ -0,0 +1,58 @@
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
const int INF = 1e9;
int main(){
int n, e;
while(cin >> n >> e){
//直接dp解决
vector<vector<int>> dp(n, vector<int>(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;
}

View File

@@ -0,0 +1,120 @@
#include <iostream>
#include <vector>
#include <queue>
#include <climits>
#include <algorithm>
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<vector<Edge>> 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<vector<Edge>> 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<vector<int>> dp(n + 1, vector<int>(2, INF));
//换乘点K
vector<int> K_record(n + 1, INF);
priority_queue<Node, vector<Node>, greater<Node>> 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;
}

View File

@@ -0,0 +1,67 @@
#include <iostream>
#include <vector>
#include <tuple>
#include <algorithm>
using namespace std;
int find(int x, vector<int>& 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<tuple<int, int, int>> edges;
vector<int> 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<int, int, int>& a, const tuple<int, int, int>& 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;
}

View File

@@ -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…n1每个房间都需要网络连接。房间 i 有网络当且仅当满足如下2个条件之一
1房间 i 安装了路由器(成本为 r
i
>0
2房间 i 和房间 j 有网线连接且房间 j 有网络(在房间 i 和房间 j 之间布置网线的成本为 f
ij
>0
假定你是赛事组委会的网络工程师,请编写程序设计一个网络布线方案(哪些房间安装路由器,哪些房间之间布置网线),使得所有房间都有网络,且总成本最小。
例如下图包含7个房间和10个可能的连接安装路由器的成本为括号内数字房间之间布置网线的成本为边的权值。其解决方案为右下图即在房间1和4安装路由器并进行图中的网线布置。总成本为120。
img.png
输入格式:
输入第一行为两个正整数n和en为房间数不超过600e为可能的连接数不超过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