PAT甲级图论相关题目:
1003 Emergency
分数 25
As an emergency rescue team leader of a city, you are given a special map of your country. The map shows several scattered cities connected by some roads. Amount of rescue teams in each city and the length of each road between any pair of cities are marked on the map. When there is an emergency call to you from some other city, your job is to lead your men to the place as quickly as possible, and at the mean time, call up as many hands on the way as possible.
Input Specification:
Each input file contains one test case. For each test case, the first line contains 4 positive integers: N (≤500) - the number of cities (and the cities are numbered from 0 to N−1), M - the number of roads,
C
1
C_1
C1and
C
2
C_2
C2- the cities that you are currently in and that you must save, respectively. The next line contains N integers, where the i-th integer is the number of rescue teams in the i-th city. Then M lines follow, each describes a road with three integers
c
1
c_1
c1,
c
2
c_2
c2and L, which are the pair of cities connected by a road and the length of that road, respectively. It is guaranteed that there exists at least one path from
C
1
C_1
C1to
C
2
C_2
C2.
Output Specification:
For each test case, print in one line two numbers: the number of different shortest paths between
C
1
C_1
C1and
C
2
C_2
C2, and the maximum amount of rescue teams you can possibly gather. All the numbers in a line must be separated by exactly one space, and there is no extra space allowed at the end of a line.
Sample Input:
5 6 0 2
1 2 1 5 3
0 1 1
0 2 2
0 3 1
1 2 1
2 4 1
3 4 1
Sample Output:
2 4
题解
1.dijkstra走一遍最短路
2.如果当前节点路径长度会被更新,那么路径数量和救援队的数量分别继承节点t的
3.如果路径长度相等,那么:当前节点的路径数量+=节点t的路径数量,当前节点路径的救援队数量取一个max和节点t的救援队数量+emergency[当前节点]
#include<iostream>
#include<vector>
#include<queue>
#include<cstring>
using namespace std;
const int N = 505, INF = 0x3f3f3f3f;
int n, m, start, last;
int g[N][N], emergency[N];
int dist[N];
bool st[N];
int cou_road[N], cou_emergency[N];
void bfs(){
memset(dist, 0x3f, sizeof dist);
dist[start] = 0;
cou_road[start] = 1;
cou_emergency[start] = emergency[start];
for(int i = 0; i < n; i ++ ){
int t = -1;
for(int j = 0; j < n; j ++ ){
if(!st[j] && (t == -1 || dist[j] < dist[t])) t = j;
}
if(t == last) break;
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];
cou_road[j] = cou_road[t];
cou_emergency[j] = cou_emergency[t] + emergency[j];
}
else if(dist[j] == dist[t] + g[t][j]){
cou_road[j] += cou_road[t];
cou_emergency[j] = max(cou_emergency[j], cou_emergency[t] + emergency[j]);
}
}
}
cout << cou_road[last] << " " << cou_emergency[last];
}
int main(){
memset(g, 0x3f, sizeof g);
cin >> n >> m >> start >> last;
for(int i = 0; i < n; i ++ ) cin >> emergency[i];
for(int i = 0; i < m; i ++ ){
int a, b, w;
cin >> a >> b >> w;
g[a][b] = w;
g[b][a] = w;
}
bfs();
return 0;
}
1013 Battle Over Cities
分数 25
It is vitally important to have all the cities connected by highways in a war. If a city is occupied by the enemy, all the highways from/toward that city are closed. We must know immediately if we need to repair any other highways to keep the rest of the cities connected. Given the map of cities which have all the remaining highways marked, you are supposed to tell the number of highways need to be repaired, quickly.
For example, if we have 3 cities and 2 highways connecting c i t y 1 city_1 city1- c i t y 2 city_2 city2and c i t y 1 city_1 city1 - c i t y 3 city_3 city3.Then if c i t y 1 city_1 city1is occupied by the enemy, we must have 1 highway repaired, that is the highway c i t y 2 city_2 city2- c i t y 3 city_3 city3.
Input Specification:
Each input file contains one test case. Each case starts with a line containing 3 numbers N (<1000), M and K, which are the total number of cities, the number of remaining highways, and the number of cities to be checked, respectively. Then M lines follow, each describes a highway by 2 integers, which are the numbers of the cities the highway connects. The cities are numbered from 1 to N. Finally there is a line containing K numbers, which represent the cities we concern.
Output Specification:
For each of the K cities, output in a line the number of highways need to be repaired if that city is lost.
Sample Input:
3 2 3
1 2
1 3
1 2 3
Sample Output:
1
0
0
题解
1.求去除相应节点,还需要连几条边才能联通,即求
(
连通块的数量
−
1
)
(连通块的数量-1)
(连通块的数量−1)
#include<iostream>
#include<queue>
#include<vector>
#include<cstring>
using namespace std;
const int N = 1E3 + 5;
int n, m, k;
vector<int>vec[N];
bool st[N];
void dfs(int root){
st[root] = true;
for(auto it : vec[root]){
if(!st[it]) dfs(it);
}
}
int main(){
cin >> n >> m >> k;
for(int i = 1; i <= m; i ++ ){
int a, b;
cin >> a >> b;
vec[a].push_back(b);
vec[b].push_back(a);
}
while(k -- ){
int x;
cin >> x;
int cnt = 0;
st[x] = true;
for(int i = 1; i <= n; i ++ ){
if(!st[i]){
dfs(i);
cnt ++;
}
}
cout << cnt - 1 << '\n';
memset(st, false, sizeof st);
}
return 0;
}
1018 Public Bike Management
分数 30
There is a public bike service in Hangzhou City which provides great convenience to the tourists from all over the world. One may rent a bike at any station and return it to any other stations in the city.
The Public Bike Management Center (PBMC) keeps monitoring the real-time capacity of all the stations. A station is said to be in perfect condition if it is exactly half-full. If a station is full or empty, PBMC will collect or send bikes to adjust the condition of that station to perfect. And more, all the stations on the way will be adjusted as well.
When a problem station is reported, PBMC will always choose the shortest path to reach that station. If there are more than one shortest path, the one that requires the least number of bikes sent from PBMC will be chosen.
The above figure illustrates an example. The stations are represented by vertices and the roads correspond to the edges. The number on an edge is the time taken to reach one end station from another. The number written inside a vertex S is the current number of bikes stored at S. Given that the maximum capacity of each station is 10. To solve the problem at S 3 S_3 S3, we have 2 different shortest paths:
PBMC -> S 1 S_1 S1-> S 3 S_3 S3. In this case, 4 bikes must be sent from PBMC, because we can collect 1 bike from S 1 S_1 S1and then take 5 bikes to S 3 S_3 S3, so that both stations will be in perfect conditions.
PBMC -> S 2 S_2 S2-> S 3 S_3 S3. This path requires the same time as path 1, but only 3 bikes sent from PBMC and hence is the one that will be chosen.
Input Specification:
Each input file contains one test case. For each case, the first line contains 4 numbers:
C
m
a
x
C_{max}
Cmax(≤100), always an even number, is the maximum capacity of each station; N (≤500), the total number of stations;
S
p
S_p
Sp, the index of the problem station (the stations are numbered from 1 to N, and PBMC is represented by the vertex 0); and M, the number of roads. The second line contains N non-negative numbers
C
i
C_i
Ci(i=1,⋯,N) where each
C
i
C_i
Ci is the current number of bikes at
S
i
S_i
Si respectively. Then M lines follow, each contains 3 numbers:
S
i
S_i
Si,
S
j
S_j
Sj, and
T
i
j
T_{ij}
Tijwhich describe the time
T
i
j
T_{ij}
Tijtaken to move betwen stations
S
i
S_i
Siand
S
j
S_j
Sj. All the numbers in a line are separated by a space.
Output Specification:
For each test case, print your results in one line. First output the number of bikes that PBMC must send. Then after one space, output the path in the format: 0−>
S
1
S_1
S1−>⋯−>
S
p
S_p
Sp. Finally after another space, output the number of bikes that we must take back to PBMC after the condition of
S
p
S_p
Sp is adjusted to perfect.
Note that if such a path is not unique, output the one that requires minimum number of bikes that we must take back to PBMC. The judge’s data guarantee that such a path is unique.
Sample Input:
10 3 3 5
6 7 0
0 1 1
0 2 1
0 3 3
1 3 1
2 3 1
Sample Output:
3 0->2->3 0
题解
1.dijkstra得到最短路
2.dfs找出the least number of bikes sent from PBMC的路径,如果不唯一就找出minimum number of bikes that we must take back to PBMC路径
3.本题如果只有Dijkstra是不可以的,因为minSeed和minBack在路径上的传递不满足最优子结构,不是简单的相加的过程,只有在所有路径都确定了之后才能区选择最小的seed和最小的back
#include<iostream>
#include<vector>
#include<cstring>
using namespace std;
const int N = 505, INF = 0x3f3f3f3f;
int n, m, total, last;
int bike[N];
bool st[N];
int g[N][N], dist[N];
int pre[N];
int res_send = INF, res_back = INF;
vector<int>res;
void bfs(){
memset(dist, 0x3f, sizeof dist);
dist[0] = 0;
for(int i = 0; i <= n; i ++ ){
int t = -1;
for(int j = 0; j <= n; j ++ ){
if(!st[j] && (t == -1 || dist[j] < dist[t])) t = j;
}
if(t == last) break;
st[t] = true;
for(int j = 0; j <= n; j ++ ){
dist[j] = min(dist[j], dist[t] + g[t][j]);
}
}
memset(st, false, sizeof st);
}
bool dfs(int root, int to_send, int to_back, int distance){
if(distance > dist[root]) return false;
st[root] = true;
if(root == last){
if(distance != dist[last]) return false;
if(to_send < res_send){
res_send = to_send, res_back = to_back;
return true;
}
if(to_send == res_send && to_back < res_back){
res_send = to_send, res_back = to_back;
return true;
}
return false;
}
bool flag = false;
for(int i = 0; i <= n; i ++ ){
if(!st[i] && g[root][i] != INF){
st[i] = true;
if(bike[i] >= total){
if(dfs(i, to_send, to_back + bike[i] - total, distance + g[root][i])){
pre[i] = root, flag = true;
}
}
else{
int difference = total - bike[i];
if(to_back >= difference){
if(dfs(i, to_send, to_back - difference, distance + g[root][i])){
pre[i] = root, flag = true;
}
}
else{
if(dfs(i, to_send + difference - to_back, 0, distance + g[root][i])){
pre[i] = root, flag = true;
}
}
}
st[i] = false;
}
}
return flag;
}
int main(){
memset(g, 0x3f, sizeof g);
cin >> total >> n >> last >> m;
total >>= 1;
for(int i = 1; i <= n; i ++ ) cin >> bike[i];
for(int i = 1; i <= m; i ++ ){
int a, b, c;
cin >> a >> b >> c;
g[a][b] = g[b][a] = c;
}
bfs();
dfs(0, 0, 0, 0);
cout << res_send << " ";
for(int i = last; i != 0; i = pre[i]) res.push_back(i);
res.push_back(0);
for(int i = res.size() - 1; i >= 0; i -- ){
printf("%d%s", res[i], i == 0 ? " " : "->");
}
cout << res_back;
return 0;
}
1021 Deepest Root
分数 25
A graph which is connected and acyclic can be considered a tree. The height of the tree depends on the selected root. Now you are supposed to find the root that results in a highest tree. Such a root is called the deepest root.
Input Specification:
Each input file contains one test case. For each case, the first line contains a positive integer N (≤
1
0
4
10^4
104) which is the number of nodes, and hence the nodes are numbered from 1 to N. Then N −1 lines follow, each describes an edge by given the two adjacent nodes’ numbers.
Output Specification:
For each test case, print each of the deepest roots in a line. If such a root is not unique, print them in increasing order of their numbers. In case that the given graph is not a tree, print Error: K components where K is the number of connected components in the graph.
Sample Input 1:
5
1 2
1 3
1 4
2 5
Sample Output 1:
3
4
5
Sample Input 2:
5
1 3
1 4
2 5
3 4
Sample Output 2:
Error: 2 components
题解
1.dfs判断它有几个连通块。如果有多个,那就输出Error: x components
2.如果只有一个,先从判断连通块的dfs中得到拥有部分最大深度的结点们,然后从任意一个开始dfs得到剩余的最大深度的节点们,这两个结点集合的并集就是所求
#include<iostream>
#include<vector>
#include<cstring>
#include<set>
using namespace std;
const int N = 1E4 + 5;
int n;
int e[N + N], ne[N + N], h[N], idx;
bool st[N];
int res, path[N], cnt, max_height;
set<int>set1;
void add(int a, int b){
e[idx] = b, ne[idx] = h[a], h[a] = idx ++;
}
void dfs(int root, int height){
if(height > max_height){
cnt = 0, path[cnt ++] = root, max_height = height;
}
else if(height == max_height) path[cnt ++] = root;
st[root] = true;
for(int i = h[root]; i != -1; i = ne[i]){
int j = e[i];
if(!st[j]) dfs(j, height + 1);
}
}
int main(){
memset(h, -1, sizeof h);
cin >> n;
for(int i = 1; i <= n - 1; i ++ ){
int a, b;
cin >> a >> b;
add(a, b);
add(b, a);
}
int cou = 0;
for(int i = 1; i <= n; i ++ ){
if(!st[i]){
dfs(i, 1);
cou ++;
}
}
if(cou != 1) printf("Error: %d components", cou);
else{
for(int i = 0; i < cnt; i ++ ) set1.insert(path[i]);
memset(st, false, sizeof st);
dfs(path[0], 1);
for(int i = 0; i < cnt; i ++ ) set1.insert(path[i]);
for(auto it : set1) printf("%d\n", it);
}
return 0;
}
1030 Travel Plan
分数 30
A traveler’s map gives the distances between cities along the highways, together with the cost of each highway. Now you are supposed to write a program to help a traveler to decide the shortest path between his/her starting city and the destination. If such a shortest path is not unique, you are supposed to output the one with the minimum cost, which is guaranteed to be unique.
Input Specification:
Each input file contains one test case. Each case starts with a line containing 4 positive integers N, M, S, and D, where N (≤500) is the number of cities (and hence the cities are numbered from 0 to N−1); M is the number of highways; S and D are the starting and the destination cities, respectively. Then M lines follow, each provides the information of a highway, in the format:
City1 City2 Distance Cost
where the numbers are all integers no more than 500, and are separated by a space.
Output Specification:
For each test case, print in one line the cities along the shortest path from the starting point to the destination, followed by the total distance and the total cost of the path. The numbers must be separated by a space and there must be no extra space at the end of output.
Sample Input:
4 5 0 3
0 1 1 20
1 3 2 30
0 3 4 10
0 2 2 20
2 3 1 20
Sample Output:
0 2 3 3 40
题解
1.dijkstra走一遍最短路,同时更新成本,并记录路径
#include<iostream>
#include<vector>
#include<cstring>
using namespace std;
const int N = 505, INF = 0x3f3f3f3f;
int n, m, start, last;
int g[N][N], dist[N];
bool st[N];
int cost[N][N], total[N], pre[N];
vector<int>res;
void bfs(){
memset(dist, 0x3f, sizeof dist);
dist[start] = 0; total[start] = 0; pre[start] = -1;
for(int i = 0; i < n; i ++ ){
int t = -1;
for(int j = 0; j < n; j ++ ){
if(!st[j] && (t == -1 || dist[j] < dist[t])) t = j;
}
if(t == last) break;
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];
total[j] = total[t] + cost[t][j];
pre[j] = t;
}
else if(dist[j] == dist[t] + g[t][j] && total[j] > total[t] + cost[t][j]){
total[j] = total[t] + cost[t][j];
pre[j] = t;
}
}
}
for(int i = last; i != -1; i = pre[i]) res.push_back(i);
for(int i = res.size() - 1; i >= 0; i -- ) printf("%d ", res[i]);
printf("%d %d", dist[last], total[last]);
}
int main(){
memset(g, 0x3f, sizeof g);
cin >> n >> m >> start >> last;
for(int i = 1; i <= m; i ++ ){
int a, b, c, d;
cin >> a >> b >> c >> d;
g[a][b] = c; cost[a][b] = d;
g[b][a] = c; cost[b][a] = d;
}
bfs();
return 0;
}
1034 Head of a Gang
分数 30
One way that the police finds the head of a gang is to check people’s phone calls. If there is a phone call between A and B, we say that A and B is related. The weight of a relation is defined to be the total time length of all the phone calls made between the two persons. A “Gang” is a cluster of more than 2 persons who are related to each other with total relation weight being greater than a given threshold K. In each gang, the one with maximum total weight is the head. Now given a list of phone calls, you are supposed to find the gangs and the heads.
Input Specification:
Each input file contains one test case. For each case, the first line contains two positive numbers N and K (both less than or equal to 1000), the number of phone calls and the weight threthold, respectively. Then N lines follow, each in the following format:
Name1 Name2 Time
where Name1 and Name2 are the names of people at the two ends of the call, and Time is the length of the call. A name is a string of three capital letters chosen from A-Z. A time length is a positive integer which is no more than 1000 minutes.
Output Specification:
For each test case, first print in a line the total number of gangs. Then for each gang, print in a line the name of the head and the total number of the members. It is guaranteed that the head is unique for each gang. The output must be sorted according to the alphabetical order of the names of the heads.
Sample Input 1:
8 59
AAA BBB 10
BBB AAA 20
AAA CCC 40
DDD EEE 5
EEE DDD 70
FFF GGG 30
GGG HHH 20
HHH FFF 10
Sample Output 1:
2
AAA 3
GGG 3
Sample Input 2:
8 70
AAA BBB 10
BBB AAA 20
AAA CCC 40
DDD EEE 5
EEE DDD 70
FFF GGG 30
GGG HHH 20
HHH FFF 10
Sample Output 2:
0
题解
1.分别定义两个map,to_id用来将名字映射成下标(从0开始),to_name用来将下标映射成名字
2.建立一个存边的结构体,
e
d
g
e
s
[
i
]
=
edges[i] =
edges[i]= {
i
d
1
,
i
d
2
,
m
i
n
u
t
e
s
id1, id2, minutes
id1,id2,minutes};分别存储每条边的两个节点和其权值
3.dfs得到
(
连通分量内成员个数
)
(连通分量内成员个数)
(连通分量内成员个数)和
(
其对应的头节点
)
(其对应的头节点)
(其对应的头节点),同时将连通分量遍历到的下标设为
t
r
u
e
true
true
4.遍历一遍存边的结构体,得到该连通分量的 total relation weight
5.If(total relation weight > K && 连通分量成员个数 > 2),那么就记录下来
#include<iostream>
#include<vector>
#include<cstring>
#include<unordered_map>
#include<algorithm>
using namespace std;
typedef pair<int,int>PII;
const int N = 2E3 + 5;
int n, k;
int g[N][N], cnt;
bool st[N], edge_st[N];
int gang[N];
unordered_map<string,int>to_id;
unordered_map<int,string>to_name;
vector<PII>res;
struct node{
int l, r, minutes;
}edges[N];
int dfs(int root, int &head){
if(gang[root] > gang[head]) head = root;
int cou = 1;
st[root] = edge_st[root] = true;
for(int i = 0; i < cnt; i ++ ){
if(g[root][i] && !st[i]) cou += dfs(i, head);
}
return cou;
}
bool cmp(PII a, PII b){
return to_name[a.first] < to_name[b.first];
}
int main(){
cin >> n >> k;
string a, b;
int call_time;
for(int i = 1; i <= n; i ++ ){
cin >> a >> b >> call_time;
if(!to_id.count(a)) to_name[cnt] = a, to_id[a] = cnt ++;
if(!to_id.count(b)) to_name[cnt] = b, to_id[b] = cnt ++;
int id1 = to_id[a], id2 = to_id[b];
g[id1][id2] += call_time, g[id2][id1] += call_time;
gang[id1] += call_time, gang[id2] += call_time;
edges[i] = {id1, id2, call_time};
}
for(int i = 0; i < cnt; i ++ ){
int total = 0, head = i;
if(!st[i]){
int cou = dfs(i, head);
for(int j = 1; j <= n; j ++ ){
if(edge_st[edges[j].l] || edge_st[edges[j].r]){
total += edges[j].minutes;
}
}
memset(edge_st, false, sizeof edge_st);
if(total > k && cou > 2) res.push_back({head, cou});
}
}
sort(res.begin(), res.end(), cmp);
int len = res.size();
cout << len << '\n';
for(int i = 0; i < len; i ++ ){
cout << to_name[res[i].first] << " " << res[i].second << '\n';
}
return 0;
}
1072 Gas Station
分数 30
A gas station has to be built at such a location that the minimum distance between the station and any of the residential housing is as far away as possible. However it must guarantee that all the houses are in its service range.
Now given the map of the city and several candidate locations for the gas station, you are supposed to give the best recommendation. If there are more than one solution, output the one with the smallest average distance to all the houses. If such a solution is still not unique, output the one with the smallest index number.
Input Specification:
Each input file contains one test case. For each case, the first line contains 4 positive integers: N (≤
1
0
3
10^3
103), the total number of houses; M (≤10), the total number of the candidate locations for the gas stations; K (≤
1
0
4
10^4
104), the number of roads connecting the houses and the gas stations; and
D
S
D_S
DS, the maximum service range of the gas station. It is hence assumed that all the houses are numbered from 1 to N, and all the candidate locations are numbered from G
1 to G
M.
Then K lines follow, each describes a road in the format
P1 P2 Dist
where P1
and P2
are the two ends of a road which can be either house numbers or gas station numbers, and Dist
is the integer length of the road.
Output Specification:
For each test case, print in the first line the index number of the best location. In the next line, print the minimum and the average distances between the solution and all the houses. The numbers in a line must be separated by a space and be accurate up to 1 decimal place. If the solution does not exist, simply output No Solution
.
Sample Input 1:
4 3 11 5
1 2 2
1 4 2
1 G1 4
1 G2 3
2 3 2
2 G2 1
3 4 2
3 G3 2
4 G1 3
G2 G1 1
G3 G2 2
Sample Output 1:
G1
2.0 3.3
Sample Input 2:
2 1 2 10
1 G1 9
2 G1 20
Sample Output 2:
No Solution
题解
1.对加油站从(1-m)进行枚举,进行dijkstra求最短路的操作。
2.每次迭代:
若所有居住点距离该加油站都<=service range,则:
- 计算出以当前加油站为起点最短路径长,最后输出的时候在除以n
- 计算出所有居住点中离它的最短距离
3.优先选:所有居住点中离它的最短距离中最大的那个;
其次:选选平均长度最小的,即最短路径的长度最短的那个
#include<iostream>
#include<unordered_map>
#include<cstring>
#include<vector>
using namespace std;
typedef pair<int,double>PID;
const int N = 1E3 + 15, INF = 0x3f3f3f3f;
int n, m, k, ds;
int g[N][N];
int dist[15][N];
bool st[15][N];
unordered_map<string,int>to_id;
void bfs(int root){
dist[root][root + n] = 0;
for(int i = 1; i <= n + m; i ++ ){
int t = -1;
for(int j = 1; j <= n + m; j ++ ){
if(!st[root][j] && (t == -1 || dist[root][j] < dist[root][t])) t = j;
}
st[root][t] = true;
for(int j = 1; j <= n + m; j ++ ){
dist[root][j] = min(dist[root][t] + g[t][j], dist[root][j]);
}
}
}
int main(){
memset(g, 0x3f, sizeof g);
memset(dist, 0x3f, sizeof dist);
cin >> n >> m >> k >> ds;
for(int i = 1; i <= 10; i ++ ) to_id["G" + to_string(i)] = n + i;
string a, b;
int c;
for(int i = 1; i <= k; i ++ ){
cin >> a >> b >> c;
int id1, id2;
if(a[0] == 'G') id1 = to_id[a];
else id1 = stoi(a);
if(b[0] == 'G') id2 = to_id[b];
else id2 = stoi(b);
g[id1][id2] = g[id2][id1] = c;
}
int pos = -1, min_distance = 0, aver_distance = INF;
for(int i = 1; i <= m; i ++ ){
bfs(i);
bool flag = false;
int tem_min = INF, tem_aver = 0;
for(int j = 1; j <= n; j ++ ){
if(dist[i][j] > ds){
flag = true;
break;
}
tem_aver += dist[i][j];
tem_min = tem_min > dist[i][j] ? dist[i][j] : tem_min;
}
if(!flag){
if(min_distance < tem_min){
pos = i, min_distance = tem_min, aver_distance = tem_aver;
}
else if(min_distance == tem_min && aver_distance > tem_aver){
pos = i, min_distance = tem_min, aver_distance = tem_aver;
}
}
}
if(pos == -1) cout << "No Solution";
else printf("G%d\n%.1lf %.1lf", pos, 1.0 * min_distance, 1.0 * aver_distance / n);
return 0;
}
1076 Forwards on Weibo
分数 30
Weibo is known as the Chinese version of Twitter. One user on Weibo may have many followers, and may follow many other users as well. Hence a social network is formed with followers relations. When a user makes a post on Weibo, all his/her followers can view and forward his/her post, which can then be forwarded again by their followers. Now given a social network, you are supposed to calculate the maximum potential amount of forwards for any specific user, assuming that only L levels of indirect followers are counted.
Input Specification:
Each input file contains one test case. For each case, the first line contains 2 positive integers: N (≤1000), the number of users; and L (≤6), the number of levels of indirect followers that are counted. Hence it is assumed that all the users are numbered from 1 to N. Then N lines follow, each in the format:
M[i] user_list[i]
where M[i]
(≤100) is the total number of people that user[i]
follows; and user_list[i]
is a list of the M[i]
users that followed by user[i]
. It is guaranteed that no one can follow oneself. All the numbers are separated by a space.
Then finally a positive K is given, followed by K UserID's
for query.
Output Specification:
For each UserID, you are supposed to print in one line the maximum potential amount of forwards this user can trigger, assuming that everyone who can view the initial post will forward it once, and that only L levels of indirect followers are counted.
Sample Input:
7 3
3 2 3 4
0
2 5 6
2 3 1
2 3 4
1 4
1 5
2 2 6
Sample Output:
4
5
题解
1.如果用bfs来搜索的话是比较容易的,只需要保证每次入队:1.只入一次 2.入队层数<=L;队列每次添加{下标,层数}
2.如果用dfs来做,那么需要注意,可能会出现有些结点走这条路超过层数限制,但是可以通过其他的路径到达;
- 如果(层数超过了L),或者(这个点之前走过,但是新路径下这个点的层数超过了之前走到这
个点的层数,说明这条路径不会在被它更新) 就return - r e t u r n = d f s ( i d , s t o r e y ) − 1 return = dfs(id,storey) - 1 return=dfs(id,storey)−1,因为初始点会被记录一次,所以需要(-1)
- 给出一个测试样例:
Sample Input:
6 3
1 2
2 3 5
1 4
1 6
1 6
0
3 1 2 6
Sample Output:
0
1
5
1.bfs
#include<iostream>
#include<vector>
#include<queue>
#include<cstring>
using namespace std;
typedef pair<int,int>PII;
const int N = 1E3 + 5;
int n, L;
bool st[N], g[N][N];
int bfs(int root){
memset(st, false, sizeof st);
queue<PII>que;
que.push({root, 0});
int cnt = 0;
st[root] = true;
while(!que.empty()){
auto Top = que.front();que.pop();
int a = Top.first, b = Top.second;
for(int j = 1; j <= n; j ++ ){
if(st[j] || !g[a][j]) continue;
st[j] = true;
if(b + 1 <= L){
que.push({j, b + 1});
cnt ++;
}
}
}
return cnt;
}
int main(){
cin >> n >> L;
for(int i = 1; i <= n; i ++ ){
int k, son;
cin >> k;
for(int j = 1; j <= k; j ++ ){
cin >> son;
g[son][i] = true;
}
}
int k;
cin >> k;
while(k -- ){
int x;
cin >> x;
cout << bfs(x) << '\n';
}
return 0;
}
2.dfs
#include<iostream>
#include<vector>
#include<queue>
#include<cstring>
using namespace std;
const int N = 1E3 + 5, INF = 0x3f3f3f3f;
int n, L;
int st[N];
vector<int>vec[N];
int dfs(int root, int storey){
if(storey > L || storey >= st[root]) return 0;
int cnt = 0;
if(st[root] == INF) cnt ++;
st[root] = storey;
for(auto it : vec[root]) cnt += dfs(it, storey + 1);
return cnt;
}
int main(){
cin >> n >> L;
for(int i = 1; i <= n; i ++ ){
int k, son;
cin >> k;
for(int j = 1; j <= k; j ++ ){
cin >> son;
vec[son].push_back(i);
}
}
int k;
cin >> k;
while(k -- ){
int x;
cin >> x;
memset(st, 0x3f, sizeof st);
cout << dfs(x, 0) - 1 << '\n';
}
return 0;
}
1087 All Roads Lead to Rome
分数 30
Indeed there are many different tourist routes from our city to Rome. You are supposed to find your clients the route with the least cost while gaining the most happiness.
Input Specification:
Each input file contains one test case. For each case, the first line contains 2 positive integers N (2≤N≤200), the number of cities, and K, the total number of routes between pairs of cities; followed by the name of the starting city. The next N−1 lines each gives the name of a city and an integer that represents the happiness one can gain from that city, except the starting city. Then K lines follow, each describes a route between two cities in the format City1 City2 Cost
. Here the name of a city is a string of 3 capital English letters, and the destination is always ROM
which represents Rome.
Output Specification:
For each test case, we are supposed to find the route with the least cost. If such a route is not unique, the one with the maximum happiness will be recommanded. If such a route is still not unique, then we output the one with the maximum average happiness – it is guaranteed by the judge that such a solution exists and is unique.
Hence in the first line of output, you must print 4 numbers: the number of different routes with the least cost, the cost, the happiness, and the average happiness (take the integer part only) of the recommanded route. Then in the next line, you are supposed to print the route in the format City1->City2->...->ROM
.
Sample Input:
6 7 HZH
ROM 100
PKN 40
GDN 55
PRS 95
BLN 80
ROM GDN 1
BLN ROM 1
HZH PKN 1
PRS ROM 2
BLN HZH 2
PKN GDN 1
HZH PRS 1
Sample Output:
3 3 195 97
HZH->PRS->ROM
题解
1.分别定义两个map,to_id用来将名字映射成下标(从0开始),to_name用来将下标映射成名字
2.dijkstra走一遍最短路,同时更新
(
最短路条数
,
(最短路条数,
(最短路条数, the maximum happiness, the maximum average happiness = the min number of city, 每个点的前驱)
#include<iostream>
#include<vector>
#include<queue>
#include<cstring>
#include<unordered_map>
using namespace std;
const int N = 205, INF = 0x3f3f3f3f;
int n, m, last;
int g[N][N], dist[N];
bool st[N];
int happy[N];
int max_happy[N], pre[N], cou_min[N], city[N];
vector<int>res;
unordered_map<string,int>to_id;
unordered_map<int,string>to_name;
void bfs(){
memset(dist, 0x3f, sizeof dist);
dist[1] = 0; pre[1] = -1; cou_min[1] = 1;
for(int i = 1; i <= n; i ++ ){
int t = -1;
for(int j = 1; j <= n; j ++ ){
if(!st[j] && (t == -1 || dist[j] < dist[t])) t = j;
}
if(t == last) break;
st[t] = true;
for(int j = 1; j <= n; j ++ ){
if(dist[j] > dist[t] + g[t][j]){
dist[j] = dist[t] + g[t][j];
cou_min[j] = cou_min[t];
max_happy[j] = max_happy[t] + happy[j];
city[j] = city[t] + 1;
pre[j] = t;
}
else if(dist[j] == dist[t] + g[t][j]){
cou_min[j] += cou_min[t];
if(max_happy[j] < max_happy[t] + happy[j]){
max_happy[j] = max_happy[t] + happy[j];
city[j] = city[t] + 1;
pre[j] = t;
}
else if(max_happy[j] == max_happy[t] + happy[j]){
if(city[j] > city[t] + 1){
city[j] = city[t] + 1;
pre[j] = t;
}
}
}
}
}
cout << cou_min[last] << " " << dist[last] << " " << max_happy[last] << " " << max_happy[last] / city[last] << '\n';
for(int i = last; i != -1; i = pre[i]) res.push_back(i);
for(int i = res.size() - 1; i >= 0; i -- ){
cout << to_name[res[i]] << (i == 0 ? "" : "->");
}
}
int main(){
memset(g, 0x3f, sizeof g);
cin >> n >> m;
string s;
cin >> s;
to_id[s] = 1, to_name[1] = s;
for(int i = 2; i <= n; i ++ ){
cin >> s >> happy[i];
to_id[s] = i, to_name[i] = s;
if(s == "ROM") last = i;
}
for(int i = 1; i <= m; i ++ ){
string a, b;
int money;
cin >> a >> b >> money;
int id1 = to_id[a], id2 = to_id[b];
g[id1][id2] = g[id2][id1] = money;
}
bfs();
return 0;
}
1091 Acute Stroke
分数 30
One important factor to identify acute stroke (急性脑卒中) is the volume of the stroke core. Given the results of image analysis in which the core regions are identified in each MRI slice, your job is to calculate the volume of the stroke core.
Input Specification:
Each input file contains one test case. For each case, the first line contains 4 positive integers: M, N, L and T, where M and N are the sizes of each slice (i.e. pixels of a slice are in an M×N matrix, and the maximum resolution is 1286 by 128); L (≤60) is the number of slices of a brain; and T is the integer threshold (i.e. if the volume of a connected core is less than T, then that core must not be counted).
Then L slices are given. Each slice is represented by an M×N matrix of 0’s and 1’s, where 1 represents a pixel of stroke, and 0 means normal. Since the thickness of a slice is a constant, we only have to count the number of 1’s to obtain the volume. However, there might be several separated core regions in a brain, and only those with their volumes no less than T are counted. Two pixels are connected and hence belong to the same region if they share a common side, as shown by Figure 1 where all the 6 red pixels are connected to the blue one.
Output Specification:
For each case, output in a line the total volume of the stroke core.
Sample Input:
3 4 5 2
1 1 1 1
1 1 1 1
1 1 1 1
0 0 1 1
0 0 1 1
0 0 1 1
1 0 1 1
0 1 0 0
0 0 0 0
1 0 1 1
0 0 0 0
0 0 0 0
0 0 0 1
0 0 0 1
1 0 0 0
Sample Output:
26
题解
1.一开始先用了dfs,最后两个样例段错误,估计是栈溢出了。之所以dfs栈溢出,是因为dfs的时候每个状态都会存储在堆栈里,就好比dfs的第一个状态,一直保存到最后整个dfs结束。
2.三维的bfs,对每一个点bfs,如果大于等于t就把结果累加。如果当前的点被被访问过就更新为false,被访问过的结点是不会再访问的。
#include<iostream>
#include<vector>
#include<queue>
#include<cstring>
using namespace std;
int n, m, L, t;
int dz[6] = {0, 0, 0, 0, -1, 1};
int dx[6] = {-1, 0, 1, 0, 0, 0};
int dy[6] = {0, 1, 0, -1, 0, 0};
bool slice[65][1300][130];
int res;
struct node{int z, x, y;};
int bfs(int a, int b, int c){
queue<node>que;
int cnt = 1;
que.push({a, b, c});
slice[a][b][c] = false;
while(!que.empty()){
auto tem = que.front();que.pop();
int z = tem.z, x = tem.x, y = tem.y;
for(int i = 0; i < 6; i ++ ){
int tz = z + dz[i], tx = x + dx[i], ty = y + dy[i];
if(tz < 1 || tz > L || tx < 1 || tx > n || ty < 1 || ty > m) continue;
if(slice[tz][tx][ty]){
cnt ++;
slice[tz][tx][ty] = false;
que.push({tz, tx, ty});
}
}
}
return cnt;
}
int main(){
cin >> n >> m >> L >> t;
for(int i = 1; i <= L; i ++ )
for(int j = 1; j <= n; j ++ )
for(int k = 1; k <= m; k ++ )
cin >> slice[i][j][k];
for(int i = 1; i <= L; i ++ )
for(int j = 1; j <= n; j ++ )
for(int k = 1; k <= m; k ++ ){
int cnt = 0;
if(slice[i][j][k]) cnt = bfs(i, j, k);
if(cnt >= t) res += cnt;
}
cout << res;
return 0;
}
1103 Integer Factorization
分数 30
The K−P factorization of a positive integer N is to write N as the sum of the P-th power of K positive integers. You are supposed to write a program to find the K−P factorization of N for any positive integers N, K and P.
Input Specification:
Each input file contains one test case which gives in a line the three positive integers N (≤400), K (≤N) and P (1<P≤7). The numbers in a line are separated by a space.
Output Specification:
For each case, if the solution exists, output in the format:
N = n[1]^P + ... n[K]^P
where n[i]
(i
= 1, …, K) is the i
-th factor. All the factors must be printed in non-increasing order.
Note: the solution may not be unique. For example, the 5-2 factorization of 169 has 9 solutions, such as
1
2
2
+
4
2
+
2
2
+
2
2
+
1
2
12^2 + 4^2 + 2^2 + 2^2 + 1^2
122+42+22+22+12, or
1
1
2
+
6
2
+
2
2
+
2
2
+
2
2
11^2 + 6^2 +2^2 + 2^2 + 2^2
112+62+22+22+22, or more. You must output the one with the maximum sum of the factors. If there is a tie, the largest factor sequence must be chosen – sequence {
a
1
,
a
2
,
⋯
,
a
K
a_1,a_2,⋯,a_K
a1,a2,⋯,aK} is said to be larger than {
b
1
,
b
2
,
⋯
,
b
K
b_1,b_2,⋯,b_K
b1,b2,⋯,bK} if there exists 1≤L≤K such that
a
i
=
b
i
a_i = b_i
ai=bi for
i
<
L
i<L
i<L and
a
L
>
b
L
a_L > b_L
aL>bL. If there is no solution, simple output Impossible
.
Sample Input 1:
169 5 2
Sample Output 1:
169 = 6^2 + 6^2 + 6^2 + 6^2 + 5^2
Sample Input 2:
169 167 3
Sample Output 2:
Impossible
题解
1.先把从n-1中可以枚举的数字存入factors[]中
2.然后dfs(匹配的值,枚举到第几个factors[],临时答案数组tem[]存储到第几位,临时答案数组tem[]内的数字总和)
3.如果匹配的值减到0并且枚举了k位,并且临时答案数组tem[]内的数字总和大于答案数组res[],则进行更新
4.最后剪枝主要是处理,最后答案数组有多个1的情况
#include<iostream>
#include<vector>
#include<queue>
#include<cstring>
#include<cmath>
using namespace std;
const int N = 405;
int n, k, p;
int res_sum;
int res[N], tem[N];
vector<int>factors;
int qpow(int a, int b){
int ans = 1;
while(b){
if(b & 1) ans = ans * a;
a = a * a;
b >>= 1;
}
return ans;
}
void init(){
for(int i = n; i >= 1; i -- ){
int num = 1;
bool flag = true;
for(int j = 1; j <= p; j ++ ){
num = num * i;
if(num > n){
flag = false;
break;
}
}
if(flag) factors.push_back(i);
}
}
void dfs(int val, int pos, int cou, int sum){
if(val == 0 && cou == k){
if(sum > res_sum){
res_sum = sum;
for(int i = 0; i < k; i ++ ) res[i] = tem[i];
}
return;
}
if(cou >= k) return;
if(factors[pos] == 1){
int num = k - cou;
if(val - num != 0) return;
for(int i = cou; i < k; i ++ ) tem[i] = 1;
val -= num;
dfs(val, pos, k, sum + num);
return;
}
for(int i = pos, len = factors.size(); i < len; i ++ ){
int num = qpow(factors[i], p);
if(val >= num){
tem[cou] = factors[i];
dfs(val - num, i, cou + 1, sum + factors[i]);
tem[cou] = 0;
}
}
}
int main(){
cin >> n >> k >> p;
init();
dfs(n, 0, 0, 0);
if(!res[0]) cout << "Impossible";
else{
printf("%d =", n);
for(int i = 0; i < k; i ++ ){
printf(" %d^%d", res[i], p);
if(i != k - 1) printf(" +");
}
}
return 0;
}
1111 Online Map
分数 30
Input our current position and a destination, an online map can recommend several paths. Now your job is to recommend two paths to your user: one is the shortest, and the other is the fastest. It is guaranteed that a path exists for any request.
Input Specification:
Each input file contains one test case. For each case, the first line gives two positive integers N (2≤N≤500), and M, being the total number of streets intersections on a map, and the number of streets, respectively. Then M lines follow, each describes a street in the format:
V1 V2 one-way length time
where V1
and V2
are the indices (from 0 to N−1) of the two ends of the street; one-way
is 1 if the street is one-way from V1
to V2
, or 0 if not; length
is the length of the street; and time
is the time taken to pass the street.
Finally a pair of source and destination is given.
Output Specification:
For each case, first print the shortest path from the source to the destination with distance D in the format:
Distance = D: source -> v1 -> ... -> destination
Then in the next line print the fastest path with total time T:
Time = T: source -> w1 -> ... -> destination
In case the shortest path is not unique, output the fastest one among the shortest paths, which is guaranteed to be unique. In case the fastest path is not unique, output the one that passes through the fewest intersections, which is guaranteed to be unique.
In case the shortest and the fastest paths are identical, print them in one line in the format:
Distance = D; Time = T: source -> u1 -> ... -> destination
Sample Input 1:
10 15
0 1 0 1 1
8 0 0 1 1
4 8 1 1 1
3 4 0 3 2
3 9 1 4 1
0 6 0 1 1
7 5 1 2 1
8 5 1 2 1
2 3 0 2 2
2 1 1 1 1
1 3 0 3 1
1 4 0 1 1
9 7 1 3 1
5 1 0 5 2
6 5 1 1 2
3 5
Sample Output 1:
Distance = 6: 3 -> 4 -> 8 -> 5
Time = 3: 3 -> 1 -> 5
Sample Input 2:
7 9
0 4 1 1 1
1 6 1 1 3
2 6 1 1 1
2 5 1 2 2
3 0 0 1 1
3 1 1 1 3
3 2 1 1 2
4 5 0 2 2
6 5 1 1 2
3 5
Sample Output 2:
Distance = 3; Time = 4: 3 -> 2 -> 5
题解
1.输入注意 one-way是1为单向边,0为双向边
2.dijkstra跑2次,第一次跑最短路的同时时间最少的路径;第二次跑时间最短同时经过的city数量最少的路径;同时记录前驱路径
3.按照格式输出即可
#include<iostream>
#include<vector>
#include<queue>
#include<cstring>
using namespace std;
const int N = 505;
int n, m, start, last;
int g1[N][N], g2[N][N];
bool st[2][N];
int dist[2][N], pre[2][N], cost[2][N];
int path[2][N], cnt1, cnt2;
void bfs1(){
dist[0][start] = 0, pre[0][start] = -1;
for(int i = 0; i < n; i ++ ){
int t = -1;
for(int j = 0; j < n; j ++ ){
if(!st[0][j] && (t == -1 || dist[0][j] < dist[0][t])) t = j;
}
if(t == last) break;
st[0][t] = true;
for(int j = 0; j < n; j ++ ){
if(dist[0][j] > dist[0][t] + g1[t][j]){
dist[0][j] = dist[0][t] + g1[t][j];
pre[0][j] = t;
cost[0][j] = cost[0][t] + g2[t][j];
}
else if(dist[0][j] == dist[0][t] + g1[t][j]){
if(cost[0][j] > cost[0][t] + g2[t][j]){
pre[0][j] = t;
cost[0][j] = cost[0][t] + g2[t][j];
}
}
}
}
for(int i = last; i != -1; i = pre[0][i]) path[0][cnt1 ++] = i;
}
void bfs2(){
dist[1][start] = 0, pre[1][start] = -1;
for(int i = 0; i < n; i ++ ){
int t = -1;
for(int j = 0; j < n; j ++ ){
if(!st[1][j] && (t == -1 || dist[1][j] < dist[1][t])) t = j;
}
if(t == last) break;
st[1][t] = true;
for(int j = 0; j < n; j ++ ){
if(dist[1][j] > dist[1][t] + g2[t][j]){
dist[1][j] = dist[1][t] + g2[t][j];
pre[1][j] = t;
cost[1][j] = cost[1][t] + 1;
}
else if(dist[1][j] == dist[1][t] + g2[t][j]){
if(cost[1][j] > cost[1][t] + 1){
pre[1][j] = t;
cost[1][j] = cost[1][t] + 1;
}
}
}
}
for(int i = last; i != -1; i = pre[1][i]) path[1][cnt2 ++] = i;
}
bool check(){
if(cnt1 != cnt2) return false;
for(int i = 0; i < cnt1; i ++ ){
if(path[1][i] != path[0][i]) return false;
}
return true;
}
int main(){
memset(g1, 0x3f, sizeof g1);
memset(g2, 0x3f, sizeof g2);
memset(dist, 0x3f, sizeof dist);
cin >> n >> m;
for(int i = 1; i <= m; i ++ ){
int a, b, c, d, e;
cin >> a >> b >> c >> d >> e;
g1[a][b] = d, g2[a][b] = e;
if(!c) g1[b][a] = d, g2[b][a] = e;
}
cin >> start >> last;
bfs1();
bfs2();
if(check()){
printf("Distance = %d; Time = %d: ", dist[0][last], dist[1][last]);
for(int i = cnt1 - 1; i >= 0; i -- ){
printf("%d%s", path[0][i], i == 0 ? "" : " -> ");
}
}
else{
printf("Distance = %d: ", dist[0][last]);
for(int i = cnt1 - 1; i >= 0; i -- ){
printf("%d%s", path[0][i], i == 0 ? "\n" : " -> ");
}
printf("Time = %d: ", dist[1][last]);
for(int i = cnt2 - 1; i >= 0; i -- ){
printf("%d%s", path[1][i], i == 0 ? "" : " -> ");
}
}
return 0;
}
1122 Hamiltonian Cycle
分数 25
The “Hamilton cycle problem” is to find a simple cycle that contains every vertex in a graph. Such a cycle is called a “Hamiltonian cycle”.
In this problem, you are supposed to tell if a given cycle is a Hamiltonian cycle.
Input Specification:
Each input file contains one test case. For each case, the first line contains 2 positive integers N (2<N≤200), the number of vertices, and M, the number of edges in an undirected graph. Then M lines follow, each describes an edge in the format Vertex1 Vertex2
, where the vertices are numbered from 1 to N. The next line gives a positive integer K which is the number of queries, followed by K lines of queries, each in the format:
n
V
1
V
2
.
.
.
V
n
n \quad V_1V_2 ...V_n
nV1V2...Vn
where n is the number of vertices in the list, and
V
i
V_i
Vi’s are the vertices on a path.
Output Specification:
For each query, print in a line YES if the path does form a Hamiltonian cycle, or NO if not.
Sample Input:
6 10
6 2
3 4
1 5
2 5
3 1
4 1
1 6
6 3
1 2
4 5
6
7 5 1 4 3 6 2 5
6 5 1 4 3 6 2
9 6 2 1 6 3 4 5 2 6
4 1 2 5 1
7 6 1 3 4 5 2 6
7 6 1 2 5 4 3 1
Sample Output:
YES
NO
NO
NO
YES
NO
题解
1. 判断是否为哈密顿环
- 头顶点与尾顶点是否相同
- 是否出现了n个不同的顶点
- 总顶点数是否刚好为n+1
- 每条边都有联通
2. 测试点4前面一直卡,后来发现输入的数据长度会大于N(200),所以将path改成了vector来输入,就AC
#include<iostream>
#include<vector>
#include<set>
#include<cstring>
using namespace std;
const int N = 205;
int n, m, k;
bool g[N][N];
bool run(){
int cou, x;
cin >> cou;
set<int>set1;
vector<int>path;
for(int i = 0; i < cou; i ++ ){
cin >> x;
path.push_back(x);
set1.insert(path[i]);
}
if(path[0] != path[path.size() - 1] || set1.size() != n || cou != n + 1) return false;
for(int i = 1; i <= cou - 1; i ++ ){
if(!g[path[i]][path[i - 1]]) return false;
}
return true;
}
int main(){
cin >> n >> m;
for(int i = 1; i <= m; i ++ ){
int a, b;
cin >> a >> b;
g[a][b] = g[b][a] = true;
}
cin >> k;
while(k -- ){
bool flag = run();
printf("%s\n", flag == true ? "YES" : "NO");
}
return 0;
}
1126 Eulerian Path
分数 25
In graph theory, an Eulerian path is a path in a graph which visits every edge exactly once. Similarly, an Eulerian circuit is an Eulerian path which starts and ends on the same vertex. They were first discussed by Leonhard Euler while solving the famous Seven Bridges of Konigsberg problem in 1736. It has been proven that connected graphs with all vertices of even degree have an Eulerian circuit, and such graphs are called Eulerian. If there are exactly two vertices of odd degree, all Eulerian paths start at one of them and end at the other. A graph that has an Eulerian path but not an Eulerian circuit is called semi-Eulerian. (Cited from https://en.wikipedia.org/wiki/Eulerian_path)
Given an undirected graph, you are supposed to tell if it is Eulerian, semi-Eulerian, or non-Eulerian.
Input Specification:
Each input file contains one test case. Each case starts with a line containing 2 numbers N (≤ 500), and M, which are the total number of vertices, and the number of edges, respectively. Then M lines follow, each describes an edge by giving the two ends of the edge (the vertices are numbered from 1 to N).
Output Specification:
For each test case, first print in a line the degrees of the vertices in ascending order of their indices. Then in the next line print your conclusion about the graph – either Eulerian, Semi-Eulerian, or Non-Eulerian. Note that all the numbers in the first line must be separated by exactly 1 space, and there must be no extra space at the beginning or the end of the line.
Sample Input 1:
7 12
5 7
1 2
1 3
2 3
2 4
3 4
5 2
7 6
6 3
4 5
6 4
5 6
Sample Output 1:
2 4 4 4 4 4 2
Eulerian
Sample Input 2:
6 10
1 2
1 3
2 3
2 4
3 4
5 2
6 3
4 5
6 4
5 6
Sample Output 2:
2 4 4 4 3 3
Semi-Eulerian
Sample Input 3:
5 8
1 2
2 5
5 4
4 1
1 3
3 2
3 4
5 3
Sample Output 3:
3 3 4 3 3
Non-Eulerian
题解
1.判断欧拉路径
- 连通图且只有偶数的度 − − − − − > -----> −−−−−>欧拉图
- 连通图且只有2个奇数的度 − − − − > ----> −−−−>半欧拉图
- 否则 − − − − − − − − − − − − > ------------> −−−−−−−−−−−−>不是欧拉图
#include<iostream>
#include<vector>
#include<queue>
#include<cstring>
using namespace std;
const int N = 505;
int n, m;
bool g[N][N], st[N];
int rd[N];
void dfs(int root){
st[root] = true;
for(int i = 1; i <= n; i ++ ){
if(g[root][i] && !st[i]) dfs(i);
}
}
int main(){
cin >> n >> m;
for(int i = 1; i <= m; i ++ ){
int a, b;
cin >> a >> b;
g[a][b] = g[b][a] = true;
rd[a] ++, rd[b] ++;
}
for(int i = 1; i <= n; i ++ ) printf("%d%s", rd[i], i == n ? "\n" : " ");
int cnt = 0, odd = 0;
for(int i = 1; i <= n; i ++ ){
if(!st[i]){
dfs(i);
cnt ++;
}
}
for(int i = 1; i <= n; i ++ ) odd += (rd[i] % 2 == 1) ? 1 : 0;
if(cnt == 1 && !odd) printf("Eulerian");
else if(cnt == 1 && odd == 2) printf("Semi-Eulerian");
else printf("Non-Eulerian");
return 0;
}
1142 Maximal Clique
分数 25
A clique is a subset of vertices of an undirected graph such that every two distinct vertices in the clique are adjacent. A maximal clique is a clique that cannot be extended by including one more adjacent vertex. (Quoted from https://en.wikipedia.org/wiki/Clique_(graph_theory))
Now it is your job to judge if a given subset of vertices can form a maximal clique.
Input Specification:
Each input file contains one test case. For each case, the first line gives two positive integers Nv (≤ 200), the number of vertices in the graph, and Ne, the number of undirected edges. Then Ne lines follow, each gives a pair of vertices of an edge. The vertices are numbered from 1 to Nv.
After the graph, there is another positive integer M (≤ 100). Then M lines of query follow, each first gives a positive number K (≤ Nv), then followed by a sequence of K distinct vertices. All the numbers in a line are separated by a space.
Output Specification:
For each of the M queries, print in a line Yes if the given subset of vertices can form a maximal clique; or if it is a clique but not a maximal clique, print Not Maximal; or if it is not a clique at all, print Not a Clique.
Sample Input:
8 10
5 6
7 8
6 4
3 6
4 5
2 3
8 2
2 7
5 3
3 4
6
4 5 4 3 6
3 2 8 7
2 2 3
1 1
3 4 3 6
3 3 2 1
Sample Output:
Yes
Yes
Yes
Yes
Not Maximal
Not a Clique
题解
1.判断团
- 如果给定数组内每个顶点都能到达其他的顶点,那么这个数组可以构成团;反之不是团
2.如果是团
- 如果还能从1-n个顶点中找到任意一个可以加入该团的顶点,那么该团不是最大团;反之就是最大团
#include<iostream>
#include<vector>
#include<cstring>
using namespace std;
const int N = 205;
int n, m, k;
bool g[N][N];
bool st[N];
int path[N];
void check(){
int cou;
cin >> cou;
for(int i = 1; i <= cou; i ++ ) cin >> path[i];
bool flag = true;
for(int i = 1; i <= cou; i ++ ){
st[path[i]] = true;
for(int j = i + 1; j <= cou; j ++ ){
if(!g[path[i]][path[j]]){
flag = false;
break;
}
}
if(!flag) break;
}
if(!flag) printf("Not a Clique\n");
else{
for(int i = 1; i <= n; i ++ ){
if(!st[i]){
st[i] = true;
int j = 1;
for(; j <= cou; j ++ ){
if(!g[i][path[j]]){
break;
}
}
if(j > cou){
flag = false;
break;
}
}
}
if(!flag) printf("Not Maximal\n");
else printf("Yes\n");
}
memset(st, false, sizeof st);
}
int main(){
cin >> n >> m;
for(int i = 1; i <= m; i ++ ){
int a, b;
cin >> a >> b;
g[a][b] = g[b][a] = true;
}
cin >> k;
while(k -- ) check();
return 0;
}
1146 Topological Order
分数 25
This is a problem given in the Graduate Entrance Exam in 2018: Which of the following is NOT a topological order obtained from the given directed graph? Now you are supposed to write a program to test each of the options.
Input Specification:
Each input file contains one test case. For each case, the first line gives two positive integers N (≤ 1,000), the number of vertices in the graph, and M (≤ 10,000), the number of directed edges. Then M lines follow, each gives the start and the end vertices of an edge. The vertices are numbered from 1 to N. After the graph, there is another positive integer K (≤ 100). Then K lines of query follow, each gives a permutation of all the vertices. All the numbers in a line are separated by a space.
Output Specification:
Print in a line all the indices of queries which correspond to “NOT a topological order”. The indices start from zero. All the numbers are separated by a space, and there must no extra space at the beginning or the end of the line. It is graranteed that there is at least one answer.
Sample Input:
6 8
1 2
1 3
5 2
5 4
2 3
2 6
3 4
6 4
6
5 2 3 6 4 1
1 5 2 3 6 4
5 1 2 6 3 4
5 1 2 3 6 4
5 2 1 6 3 4
1 2 3 4 5 6
Sample Output:
0 4 5
题解
1.每次选中某个点后要将它所指向的所有结点的入度-1,如果当前结点的入度不为0则表示不是拓扑序列,如果出现过入度不为0的点则不是拓扑序列
#include<iostream>
#include<cstring>
#include<vector>
using namespace std;
const int N = 1E4 + 5;
int n, m, k;
int rd[N];
vector<int>g[N], res;
bool check(){
bool flag = false;
vector<int>tem(rd, rd + n + 1);
for(int i = 1, x; i <= n; i ++ ){
cin >> x;
if(tem[x]) flag = true;
else{
for(auto it : g[x]) tem[it] --;
}
}
return flag;
}
int main(){
cin >> n >> m;
for(int i = 1; i <= m; i ++ ){
int a, b;
cin >> a >> b;
g[a].push_back(b);
rd[b] ++;
}
cin >> k;
for(int i = 0; i < k; i ++ ){
if(check()) res.push_back(i);
}
for(int i = 0, len = res.size(); i < len; i ++ ){
printf("%d%s", res[i], i == len - 1 ? "" : " ");
}
return 0;
}
1150 Travelling Salesman Problem
分数 25
The “travelling salesman problem” asks the following question: “Given a list of cities and the distances between each pair of cities, what is the shortest possible route that visits each city and returns to the origin city?” It is an NP-hard problem in combinatorial optimization, important in operations research and theoretical computer science. (Quoted from “https://en.wikipedia.org/wiki/Travelling_salesman_problem”.)
In this problem, you are supposed to find, from a given list of cycles, the one that is the closest to the solution of a travelling salesman problem.
Input Specification:
Each input file contains one test case. For each case, the first line contains 2 positive integers N (2<N≤200), the number of cities, and M, the number of edges in an undirected graph. Then M lines follow, each describes an edge in the format City1 City2 Dist
, where the cities are numbered from 1 to N and the distance Dist
is positive and is no more than 100. The next line gives a positive integer K which is the number of paths, followed by K lines of paths, each in the format:
n
C
1
C
2
.
.
.
C
n
n\quad C_1C_2...C_n
nC1C2...Cn
where n is the number of cities in the list, and
C
i
C_i
Ci’s are the cities on a path.
Output Specification:
For each path, print in a line Path X: TotalDist (Description)
where X
is the index (starting from 1) of that path, TotalDist
its total distance (if this distance does not exist, output NA
instead), and Description
is one of the following:
-
TS simple cycle
if it is a simple cycle that visits every city; -
TS cycle
if it is a cycle that visits every city, but not a simple cycle; -
Not a TS cycle
if it is NOT a cycle that visits every city.
Finally print in a lineShortest Dist(X) = TotalDist
whereX
is the index of the cycle that is the closest to the solution of a travelling salesman problem, andTotalDist
is its total distance. It is guaranteed that such a solution is unique.
Sample Input:
6 10
6 2 1
3 4 1
1 5 1
2 5 1
3 1 8
4 1 6
1 6 1
6 3 1
1 2 1
4 5 1
7
7 5 1 4 3 6 2 5
7 6 1 3 4 5 2 6
6 5 1 4 3 6 2
9 6 2 1 6 3 4 5 2 6
4 1 2 5 1
7 6 1 2 5 4 3 1
7 6 3 2 5 4 1 6
Sample Output:
Path 1: 11 (TS simple cycle)
Path 2: 13 (TS simple cycle)
Path 3: 10 (Not a TS cycle)
Path 4: 8 (TS cycle)
Path 5: 3 (Not a TS cycle)
Path 6: 13 (Not a TS cycle)
Path 7: NA (Not a TS cycle)
Shortest Dist(4) = 8
题解
1.Description is one of the following:
- TS simple cycle:1.头顶点=尾顶点 2.恰有n+1个顶点 3.每个顶点都遍历到4.相邻顶点必有边
- TS cycle: 1.头顶点=尾顶点 2.≠n+1个顶点 3.每个顶点都遍历到4.相邻顶点必有边
- Not a TS cycle: 否则就是
#include<iostream>
#include<cstring>
#include<vector>
#include<set>
using namespace std;
const int N = 200 + 5, INF = 0x3f3f3f3f;
int n, m, q;
int g[N][N];
int pos, res = INF;
int main(){
cin >> n >> m;
for(int i = 1; i <= m; i ++ ){
int a, b, c;
cin >> a >> b >> c;
g[a][b] = g[b][a] = c;
}
cin >> q;
for(int i = 1, k; i <= q; i ++ ){
cin >> k;
vector<int>tem;
set<int>set1;
for(int j = 1, x; j <= k; j ++ ){
cin >> x;
tem.push_back(x);
set1.insert(x);
}
bool flag = true;
int sum = 0;
for(int j = 0; j <= tem.size() - 2; j ++ ){
if(g[tem[j]][tem[j + 1]]) sum += g[tem[j]][tem[j + 1]];
else{
flag = false;
break;
}
}
if(!flag) printf("Path %d: NA (Not a TS cycle)\n", i);
else{
if(k == n + 1 && tem[0] == tem[k - 1] && set1.size() == n){
if(sum < res) res = sum, pos = i;
printf("Path %d: %d (TS simple cycle)\n", i, sum);
}
else if(k != n + 1 && tem[0] == tem[k - 1] && set1.size() == n){
if(sum < res) res = sum, pos = i;
printf("Path %d: %d (TS cycle)\n", i, sum);
}
else printf("Path %d: %d (Not a TS cycle)\n", i, sum);
}
}
printf("Shortest Dist(%d) = %d", pos, res);
return 0;
}
1131 Subway Map
分数 30
In the big cities, the subway systems always look so complex to the visitors. To give you some sense, the following figure shows the map of Beijing subway. Now you are supposed to help people with your computer skills! Given the starting position of your user, your task is to find the quickest way to his/her destination.
Input Specification:
Each input file contains one test case. For each case, the first line contains a positive integer N (≤ 100), the number of subway lines. Then N lines follow, with the i-th (i=1,⋯,N) line describes the i-th subway line in the format:
M S[1] S[2] ... S[M]
where M (≤ 100) is the number of stops, and S[i]'s (i=1,⋯,M) are the indices of the stations (the indices are 4-digit numbers from 0000 to 9999) along the line. It is guaranteed that the stations are given in the correct order – that is, the train travels between S[i] and S[i+1] (i=1,⋯,M−1) without any stop.
Note: It is possible to have loops, but not self-loop (no train starts from S and stops at S without passing through another station). Each station interval belongs to a unique subway line. Although the lines may cross each other at some stations (so called “transfer stations”), no station can be the conjunction of more than 5 lines.
After the description of the subway, another positive integer K (≤ 10) is given. Then K lines follow, each gives a query from your user: the two indices as the starting station and the destination, respectively.
The following figure shows the sample map.
Note: It is guaranteed that all the stations are reachable, and all the queries consist of legal station numbers.
Output Specification:
For each query, first print in a line the minimum number of stops. Then you are supposed to show the optimal path in a friendly format as the following:
Take Line#X1 from S1 to S2.
Take Line#X2 from S2 to S3.
......
where Xi’s are the line numbers and Si’s are the station indices. Note: Besides the starting and ending stations, only the transfer stations shall be printed.
If the quickest path is not unique, output the one with the minimum number of transfers, which is guaranteed to be unique.
Sample Input:
4
7 1001 3212 1003 1204 1005 1306 7797
9 9988 2333 1204 2006 2005 2004 2003 2302 2001
13 3011 3812 3013 3001 1306 3003 2333 3066 3212 3008 2302 3010 3011
4 6666 8432 4011 1306
3
3011 3013
6666 2001
2004 3001
Sample Output:
2
Take Line#3 from 3011 to 3013.
10
Take Line#4 from 6666 to 1306.
Take Line#3 from 1306 to 2302.
Take Line#2 from 2302 to 2001.
6
Take Line#2 from 2004 to 1204.
Take Line#1 from 1204 to 1306.
Take Line#3 from 1306 to 3001.
题解
这道题建图比较特殊:
- 通过给每条线路上的任意两个站点都添加边来建图
- 问题就转化为求最短路相同时,边数最少的的路径
- 选择邻接表存储图,添加边时,需要考虑回路和非回路的区别,如果是回路选择走最短距离的方向
- dijkstra堆优化
#include<iostream>
#include<cstring>
#include<vector>
#include<queue>
using namespace std;
typedef pair<int,int>PII;
const int N = 1E6 + 5, M = 1E4 + 5;
int n, q;
int e[N], ne[N], line[N], w[N], h[M], idx;
int stops[105];
bool st[M];
int dist[M], pre[M], transfer[M];
char ans[M][50];
void add(int a, int b, int c, int d){
e[idx] = b, w[idx] = c, line[idx] = d, ne[idx] = h[a], h[a] = idx ++;
}
void bfs(int start, int last){
memset(dist, 0x3f, sizeof dist);
memset(transfer, 0x3f, sizeof transfer);
memset(st, false, sizeof st);
priority_queue<PII,vector<PII>,greater<PII>>heap;
dist[start] = transfer[start] = 0;
heap.push({0, start});
while(!heap.empty()){
auto tem = heap.top();heap.pop();
int ver = tem.second, distance = tem.first;
if(ver == last) break;
if(st[ver]) continue;
st[ver] = true;
for(int i = h[ver]; i != -1; i = ne[i]){
int j = e[i];
if(dist[j] > distance + w[i]){
dist[j] = distance + w[i];
pre[j] = ver;
transfer[j] = transfer[ver] + 1;
sprintf(ans[j], "Take Line#%d from %04d to %04d.", line[i], ver, j);
heap.push({dist[j], j});
}
else if(dist[j] == distance + w[i]){
if(transfer[j] > transfer[ver] + 1){
pre[j] = ver;
transfer[j] = transfer[ver] + 1;
sprintf(ans[j], "Take Line#%d from %04d to %04d.", line[i], ver, j);
}
}
}
}
vector<string>res;
printf("%d\n", dist[last]);
for(int i = last; i != start; i = pre[i]) res.push_back(ans[i]);
for(int i = res.size() - 1; i >= 0; i -- ) cout << res[i] << '\n';
}
int main(){
memset(h, -1, sizeof h);
cin >> n;
for(int i = 1, k; i <= n; i ++ ){
cin >> k;
for(int j = 0; j < k; j ++ ) cin >> stops[j];
for(int j = 0, len; j < k; j ++ ){
for(int d = 0; d < j; d ++ ){
if(stops[0] != stops[k - 1]) len = j - d;
else len = min(j - d, k - 1 - j + d);
add(stops[d], stops[j], len, i);
add(stops[j], stops[d], len, i);
}
}
}
cin >> q;
while(q -- ){
int a, b;
cin >> a >> b;
bfs(a, b);
}
return 0;
}
1154 Vertex Coloring
分数 25
A proper vertex coloring is a labeling of the graph’s vertices with colors such that no two vertices sharing the same edge have the same color. A coloring using at most k colors is called a (proper) k-coloring.
Now you are supposed to tell if a given coloring is a proper k-coloring.
Input Specification:
Each input file contains one test case. For each case, the first line gives two positive integers N and M (both no more than
1
0
4
10^4
104), being the total numbers of vertices and edges, respectively. Then M lines follow, each describes an edge by giving the indices (from 0 to N−1) of the two ends of the edge.
After the graph, a positive integer K (≤ 100) is given, which is the number of colorings you are supposed to check. Then K lines follow, each contains N colors which are represented by non-negative integers in the range of int. The i-th color is the color of the i-th vertex.
Output Specification:
For each coloring, print in a line k-coloring if it is a proper k-coloring for some positive k, or No if not.
Sample Input:
10 11
8 7
6 8
4 5
8 4
8 1
1 2
1 4
9 8
9 1
1 0
2 4
4
0 1 0 1 4 1 0 1 3 0
0 1 0 1 4 1 0 1 0 0
8 1 0 1 4 1 0 5 3 0
1 2 3 4 5 6 7 8 8 9
Sample Output:
4-coloring
No
6-coloring
No
题解
1.定义一个结构体记录连通的边
2.遍历每一条边,如果出现颜色相同就return=No
#include<iostream>
#include<vector>
#include<cstring>
#include<set>
using namespace std;
const int N = 1E4 + 5;
int n, m, q;
int color[N];
struct node{
int l, r;
}stu[N];
int main(){
cin >> n >> m;
for(int i = 1; i <= m; i ++ ){
int a, b;
cin >> a >> b;
stu[i] = {a, b};
}
cin >> q;
while(q -- ){
set<int>set1;
for(int i = 0; i < n; i ++ ) cin >> color[i], set1.insert(color[i]);
bool flag = true;
for(int i = 1; i <= m; i ++ ){
if(color[stu[i].l] == color[stu[i].r]){
flag = false;
break;
}
}
if(flag) printf("%d-coloring\n", set1.size());
else printf("No\n");
}
return 0;
}
1158 Telefraud Detection
分数 25
Telefraud(电信诈骗) remains a common and persistent problem in our society. In some cases, unsuspecting victims lose their entire life savings. To stop this crime, you are supposed to write a program to detect those suspects from a huge amount of phone call records.
A person must be detected as a suspect if he/she makes more than K short phone calls to different people everyday, but no more than 20% of these people would call back. And more, if two suspects are calling each other, we say they might belong to the same gang. A makes a short phone call to B means that the total duration of the calls from A to B is no more than 5 minutes.
Input Specification:
Each input file contains one test case. For each case, the first line gives 3 positive integers K (≤500, the threshold(阈值) of the amount of short phone calls), N (≤
1
0
3
10^3
103, the number of different phone numbers), and M (≤
1
0
5
10^5
105, the number of phone call records). Then M lines of one day’s records are given, each in the format:
caller receiver duration
where caller and receiver are numbered from 1 to N, and duration is no more than 1440 minutes in a day.
Output Specification:
Print in each line all the detected suspects in a gang, in ascending order of their numbers. The gangs are printed in ascending order of their first members. The numbers in a line must be separated by exactly 1 space, and there must be no extra space at the beginning or the end of the line.
If no one is detected, output None instead.
Sample Input 1:
5 15 31
1 4 2
1 5 2
1 5 4
1 7 5
1 8 3
1 9 1
1 6 5
1 15 2
1 15 5
3 2 2
3 5 15
3 13 1
3 12 1
3 14 1
3 10 2
3 11 5
5 2 1
5 3 10
5 1 1
5 7 2
5 6 1
5 13 4
5 15 1
11 10 5
12 14 1
6 1 1
6 9 2
6 10 5
6 11 2
6 12 1
6 13 1
Sample Output 1:
3 5
6
Note: In sample 1, although 1 had 9 records, but there were 7 distinct receivers, among which 5 and 15 both had conversations lasted more than 5 minutes in total. Hence 1 had made 5 short phone calls and didn’t exceed the threshold 5, and therefore is not a suspect.
Sample Input 2:
5 7 8
1 2 1
1 3 1
1 4 1
1 5 1
1 6 1
1 7 1
2 1 1
3 1 1
Sample Output 2:
None
题解
1.如果是嫌疑犯:
- 给不同的人的short phone的个数 >=k; short phone 定义为: duration <= 5
- 这些不同的人中,回电话的人数<=20%
2.如果嫌疑犯之间在一个gang:
- 两个嫌疑犯之间有通话记录
代码实现:
1.check()函数实现对嫌疑犯的判断
2.dfs()函数进行对嫌疑犯之间进行联通,同时sort排序存入二维vector:res中
3.最后输出在sort一遍二维vector,然后输出即可
#include<iostream>
#include<vector>
#include<cstring>
#include<algorithm>
#include<set>
using namespace std;
const int N = 1E3 + 5;
int n, m, k;
int g[N][N];
bool st[N];
vector<int>tem;
vector<vector<int>>res;
bool check(int root){
int cnt1 = 0, cnt2 = 0;
for(int i = 1; i <= n; i ++ ){
if(g[root][i] && g[root][i] <= 5){
cnt1 ++;
if(g[i][root]) cnt2 ++;
}
}
if(cnt1 > k && cnt2 <= 0.2 * cnt1) return true;
return false;
}
void dfs(int root, vector<int>&ver){
st[root] = true;
ver.push_back(root);
for(int i = 0, len = tem.size(); i < len; i ++ ){
if(!st[tem[i]] && g[root][tem[i]] && g[tem[i]][root]){
dfs(tem[i], ver);
}
}
}
int main(){
cin >> k >> n >> m;
for(int i = 1; i <= m; i ++ ){
int a, b, c;
cin >> a >> b >> c;
g[a][b] += c;
}
for(int i = 1; i <= n; i ++ ){
if(check(i)) tem.push_back(i);
}
for(int i = 0, len = tem.size(); i < len; i ++ ){
if(!st[tem[i]]){
vector<int>ver;
dfs(tem[i], ver);
sort(ver.begin(), ver.end());
res.push_back(ver);
}
}
if(!res.size()) printf("None");
else{
sort(res.begin(), res.end());
for(int i = 0, len1 = res.size(); i < len1; i ++ ){
for(int j = 0, len = res[i].size(); j < len; j ++ ){
printf("%d%s", res[i][j], j == len - 1 ? "\n" : " ");
}
}
}
return 0;
}
1163 Dijkstra Sequence
分数 30
Dijkstra’s algorithm is one of the very famous greedy algorithms.
It is used for solving the single source shortest path problem which gives the shortest paths from one particular source vertex to all the other vertices of the given graph. It was conceived by computer scientist Edsger W. Dijkstra in 1956 and published three years later.
In this algorithm, a set contains vertices included in shortest path tree is maintained. During each step, we find one vertex which is not yet included and has a minimum distance from the source, and collect it into the set. Hence step by step an ordered sequence of vertices, let’s call it Dijkstra sequence, is generated by Dijkstra’s algorithm.
On the other hand, for a given graph, there could be more than one Dijkstra sequence. For example, both { 5, 1, 3, 4, 2 } and { 5, 3, 1, 2, 4 } are Dijkstra sequences for the graph, where 5 is the source. Your job is to check whether a given sequence is Dijkstra sequence or not.
Input Specification:
Each input file contains one test case. For each case, the first line contains two positive integers
N
v
N_v
Nv(≤
1
0
3
10^3
103) and Ne(≤
1
0
5
10^5
105), which are the total numbers of vertices and edges, respectively. Hence the vertices are numbered from 1 to
N
v
N_v
Nv.
Then N e N_e Ne lines follow, each describes an edge by giving the indices of the vertices at the two ends, followed by a positive integer weight (≤100) of the edge. It is guaranteed that the given graph is connected.
Finally the number of queries, K, is given as a positive integer no larger than 100, followed by K lines of sequences, each contains a permutationof the N v N_v Nv vertices. It is assumed that the first vertex is the source for each sequence.
All the inputs in a line are separated by a space.
Output Specification:
For each of the K sequences, print in a line Yes
if it is a Dijkstra sequence, or No
if not.
Sample Input:
5 7
1 2 2
1 5 1
2 3 1
2 4 1
2 5 2
3 5 1
3 4 1
4
5 1 3 4 2
5 3 1 2 4
2 3 4 5 1
3 2 1 5 4
Sample Output:
Yes
Yes
Yes
No
题解
1.对每一个序列走一遍dijkstra最短路
2.如果后面的序列dist[]小于前面,说明No
#include<iostream>
#include<queue>
#include<cstring>
using namespace std;
const int N = 1E3 + 5;
int n, m, k;
int g[N][N];
vector<int>vec[N];
int dist[N];
int path[N];
bool st[N];
bool bfs(){
for(int i = 1; i <= n; i ++ ) cin >> path[i];
memset(dist, 0x3f, sizeof dist);
memset(st, false, sizeof st);
dist[path[1]] = 0;
for(int i = 1; i <= n; i ++ ){
int t = -1;
for(int j = 1; j <= n; j ++ ){
if(!st[j] && (t == -1 || dist[j] < dist[t])) t = j;
}
st[t] = true;
for(auto it : vec[t]){
dist[it] = min(dist[it], dist[t] + g[t][it]);
}
}
for(int i = 2; i <= n; i ++ ){
if(dist[path[i]] < dist[path[i - 1]]) return false;
}
return true;
}
int main(){
memset(g, 0x3f, sizeof g);
cin >> n >> m;
for(int i = 1; i <= m; i ++ ){
int a, b, c;
cin >> a >> b >> c;
vec[a].push_back(b);g[a][b] = c;
vec[b].push_back(a);g[b][a] = c;
}
cin >> k;
while(k -- ){
bool flag = bfs();
printf("%s\n", flag == true ? "Yes" : "No");
}
return 0;
}
1166 Summit
分数 25
A summit (峰会) is a meeting of heads of state or government. Arranging the rest areas for the summit is not a simple job. The ideal arrangement of one area is to invite those heads so that everyone is a direct friend of everyone.
Now given a set of tentative arrangements, your job is to tell the organizers whether or not each area is all set.
Input Specification:
Each input file contains one test case. For each case, the first line gives two positive integers N (≤ 200), the number of heads in the summit, and M, the number of friendship relations. Then M lines follow, each gives a pair of indices of the heads who are friends to each other. The heads are indexed from 1 to N.
Then there is another positive integer K (≤ 100), and K lines of tentative arrangement of rest areas follow, each first gives a positive number L (≤ N), then followed by a sequence of L distinct indices of the heads. All the numbers in a line are separated by a space.
Output Specification:
For each of the K areas, print in a line your advice in the following format:
- if in this area everyone is a direct friend of everyone, and no friend is missing (that is, no one else is a direct friend of everyone in this area), print
Area X is OK.
. - if in this area everyone is a direct friend of everyone, yet there are some other heads who may also be invited without breaking the ideal arrangement, print
Area X may invite more people, such as H.
whereH
is the smallest index of the head who may be invited.\ - if in this area the arrangement is not an ideal one, then print
Area X needs help.
so the host can provide some special service to help the heads get to know each other.
Here X
is the index of an area, starting from 1 to K
.
Sample Input:
8 10
5 6
7 8
6 4
3 6
4 5
2 3
8 2
2 7
5 3
3 4
6
4 5 4 3 6
3 2 8 7
2 2 3
1 1
2 4 6
3 3 2 1
Sample Output:
Area 1 is OK.
Area 2 is OK.
Area 3 is OK.
Area 4 is OK.
Area 5 may invite more people, such as 3.
Area 6 needs help.
题解
1.水题
#include<iostream>
#include<vector>
#include<cstring>
using namespace std;
const int N = 205;
int n, m, q;
bool g[N][N];
bool st[N];
int path[N];
int main(){
cin >> n >> m;
for(int i = 1; i <= m; i ++ ){
int a, b;
cin >> a >> b;
g[a][b] = g[b][a] = true;
}
cin >> q;
for(int i = 1, k; i <= q; i ++ ){
cin >> k;
memset(st, false, sizeof st);
for(int j = 1; j <= k; j ++ ) cin >> path[j];
bool flag = true;
for(int j = 1; j <= k; j ++ ){
st[path[j]] = true;
for(int d = j + 1; d <= k; d ++ ){
if(!g[path[j]][path[d]]){
flag = false;
break;
}
}
if(!flag) break;
}
if(!flag) printf("Area %d needs help.\n", i);
else{
int pos = 0;
for(int j = 1; j <= n; j ++ ){
if(!st[j]){
int d;
for(d = 1; d <= k; d ++ ){
if(!g[j][path[d]]) break;
}
if(d > k){
pos = j;
break;
}
}
}
if(!pos) printf("Area %d is OK.\n", i);
else printf("Area %d may invite more people, such as %d.\n", i, pos);
}
}
return 0;
}
1170 Safari Park
分数 25
A safari park(野生动物园)has K species of animals, and is divided into N regions. The managers hope to spread the animals to all the regions, but not the same animals in the two neighboring regions. Of course, they also realize that this is an NP complete problem, you are not expected to solve it. Instead, they have designed several distribution plans. Your job is to write a program to help them tell if a plan is feasible.
Input Specification:
Each input file contains one test case. For each case, the first line gives 3 integers: N (0<N≤500), the number of regions; R (≥0), the number of neighboring relations, and K (0<K≤N), the number of species of animals. The regions and the species are both indexed from 1 to N.
Then R lines follow, each gives the indices of a pair of neighboring regions, separated by a space.
Finally there is a positive M (≤20) followed by M lines of distribution plans. Each plan gives N indices of species in a line (the i-th index is the animal in the i-th rigion), separated by spaces. It is guaranteed that any pair of neighboring regions must be different, and there is no duplicated neighboring relations.
Output Specification:
For each plan, print in a line Yes
if no animals in the two neighboring regions are the same, or No
otherwise. However, if the number of species given in a plan is not K, you must print Error: Too many species.
or Error: Too few species.
according to the case.
Sample Input:
6 8 3
2 1
1 3
4 6
2 5
2 4
5 4
5 6
3 6
5
1 2 3 3 1 2
1 2 3 4 5 6
4 5 6 6 4 5
2 3 4 2 3 4
2 2 2 2 2 2
Sample Output:
Yes
Error: Too many species.
Yes
No
Error: Too few species.
题解
1.用set存储标记color,如果>K,就太多;如果<K,就太少;
如果相等:
- 如果两个顶点有边,且标记color也相同,说明No
- 反之就是Yes**
#include<iostream>
#include<cstring>
#include<vector>
#include<set>
using namespace std;
const int N = 505;
int n, m, k, q;
bool g[N][N];
int color[N];
int main(){
cin >> n >> m >> k;
for(int i = 1; i <= m; i ++ ){
int a, b;
cin >> a >> b;
g[a][b] = g[b][a] = true;
}
cin >> q;
while(q -- ){
set<int>set1;
for(int i = 1; i <= n; i ++ ) cin >> color[i], set1.insert(color[i]);
if(set1.size() > k) printf("Error: Too many species.\n");
else if(set1.size() < k) printf("Error: Too few species.\n");
else{
bool flag = true;
for(int i = 1; i <= n; i ++ ){
for(int j = 1; j <= n; j ++ ){
if(i != j){
if(g[i][j] && color[i] == color[j]){
flag = false;
break;
}
}
}
if(!flag) break;
}
printf("%s\n", flag == true ? "Yes" : "No");
}
}
return 0;
}
1171 Replacement Selection
分数 30
When the input is much too large to fit into memory, we have to do external sorting instead of internal sorting. One of the key steps in external sorting is to generate sets of sorted records (also called runs) with limited internal memory. The simplest method is to read as many records as possible into the memory, and sort them internally, then write the resulting run back to some tape. The size of each run is the same as the capacity of the internal memory.
Replacement Selection sorting algorithm was described in 1965 by Donald Knuth. Notice that as soon as the first record is written to an output tape, the memory it used becomes available for another record. Assume that we are sorting in ascending order, if the next record is not smaller than the record we have just output, then it can be included in the run.
For example, suppose that we have a set of input { 81, 94, 11, 96, 12, 99, 35 }, and our memory can sort 3 records only. By the simplest method we will obtain three runs: { 11, 81, 94 }, { 12, 96, 99 } and { 35 }. According to the replacement selection algorithm, we would read and sort the first 3 records { 81, 94, 11 } and output 11 as the smallest one. Then one space is available so 96 is read in and will join the first run since it is larger than 11. Now we have { 81, 94, 96 }. After 81 is out, 12 comes in but it must belong to the next run since it is smaller than 81. Hence we have { 94, 96, 12 } where 12 will stay since it belongs to the next run. When 94 is out and 99 is in, since 99 is larger than 94, it must belong to the first run. Eventually we will obtain two runs: the first one contains { 11, 81, 94, 96, 99 } and the second one contains { 12, 35 }.
Your job is to implement this replacement selection algorithm.
Input Specification:
Each input file contains several test cases. The first line gives two positive integers N (≤
1
0
5
10^5
105) and M (<N/2), which are the total number of records to be sorted, and the capacity of the internal memory. Then N numbers are given in the next line, all in the range of int. All the numbers in a line are separated by a space.
Output Specification:
For each test case, print in each line a run (in ascending order) generated by the replacement selection algorithm. All the numbers in a line must be separated by exactly 1 space, and there must be no extra space at the beginning or the end of the line.
Sample Input:
13 3
81 94 11 96 12 99 17 35 28 58 41 75 15
Sample Output:
11 81 94 96 99
12 17 28 35 41 58 75
15
题解
1.定义2个小根堆,heap1为当前run的序列,heap2为下一次run的序列
2.将前m个数字加入到heap1
3.然后从m+1往后遍历:
- 如果当前的数字>=heap1.top, 那么插入heap1
- 否则,插入heap2
4.如果heap1空了,那么swap(heap1,heap2),将下一次run的数据换到heap1上来进行遍历
#include<iostream>
#include<cstring>
#include<queue>
using namespace std;
const int N = 1E5 + 5;
int n, m;
int arr[N];
priority_queue<int,vector<int>,greater<int>>heap1, heap2;
int main(){
cin >> n >> m;
for(int i = 1; i <= n; i ++ ) cin >> arr[i];
for(int i = 1; i <= m; i ++ ) heap1.push(arr[i]);
int i = m + 1;
while(!heap1.empty()){
int x = heap1.top();heap1.pop();
printf("%d", x);
if(i <= n){
if(arr[i] >= x) heap1.push(arr[i]);
else heap2.push(arr[i]);
++ i;
}
if(!heap1.empty()) printf(" ");
else{
swap(heap1, heap2);
printf("\n");
}
}
return 0;
}
1175 Professional Ability Test
分数 30
Professional Ability Test (PAT) consists of several series of subject tests. Each test is divided into several levels. Level A is a prerequisite (前置要求)
of Level B if one must pass Level A with a score no less than S in order to be qualified to take Level B. At the mean time, one who passes Level A with a score no less than S will receive a voucher(代金券)of D yuans (Chinese dollar) for taking Level B.
At the moment, this PAT is only in design and hence people would make up different plans. A plan is NOT
consistent if there exists some test T so that T is a prerequisite of itself. Your job is to test each plan and tell if it is a consistent one, and at the mean time, find the easiest way (with minimum total S) to obtain the certificate of any subject test. If the easiest way is not unique, find the one that one can win the maximum total value of vouchers.
Input Specification:
Each input file contains one test case. For each case, the first line gives two positive integers N (≤1000) and M, being the total numbers of tests and prerequisite relations, respectively. Then M lines follow, each describes a prerequisite relation in the following format:
T1 T2 S D
where T1
and T2
are the indices (from 0 to N−1) of the two distinct tests; S
is the minimum score (in the range (0, 100]) required to pass T1
in order to be qualified to take T2
; and D
is the value of the voucher (in the range (0, 500]) one can receive if one passes T1
with a score no less than S
and plan to take T2
. It is guaranteed that at most one pair of S
and D
are defined for a prerequisite relation.
Then another positive integer K (≤N) is given, followed by K queries of tests. All the numbers in a line are separated by spaces.
Output Specification:
Print in the first line Okay
. if the whole plan is consistent, or Impossible
. if not.
If the plan is consistent, for each query of test T
, print in a line the easiest way to obtain the certificate of this test, in the format:
T0->T1->...->T
However, if T
is the first level of some subject test (with no prerequisite), print You may take test T directly.
instead.
If the plan is impossible, for each query of test T
, check if one can take it directly or not. If the answer is yes, print in a line You may take test T directly.
; or print Error.
instead.
Sample Input 1:
8 15
0 1 50 50
1 2 20 20
3 4 90 90
3 7 90 80
4 5 20 20
7 5 10 10
5 6 10 10
0 4 80 60
3 1 50 45
1 4 30 20
1 5 50 20
2 4 10 10
7 2 10 30
2 5 30 20
2 6 40 60
8
0 1 2 3 4 5 6 7
Sample Output 1:
Okay.
You may take test 0 directly.
0->1
0->1->2
You may take test 3 directly.
0->1->2->4
0->1->2->4->5
0->1->2->6
3->7
Sample Input 2:
4 5
0 1 1 10
1 2 2 10
3 0 4 10
3 2 5 10
2 0 3 10
2
3 1
Sample Output 2:
Impossible.
You may take test 3 directly.
Error.
题解
1.正向建图,选出入度为0的点(每个点被更新只能从这几个点中选一个出发),提前放入优先队列, dijkstra跑一遍,求出满足 最小total_S;最小total_S相同时,最大代金券的路径
2.做一遍拓扑排序求环:文章来源:https://www.toymoban.com/news/detail-811648.html
- 如果没环return = true
- 如果有环,则将其中不在环内的正常点(即为拓扑排序的数组内)放入Not_error[]数组
输出:文章来源地址https://www.toymoban.com/news/detail-811648.html
- 如果该点入度为0,则 return = printf(“You may take test %d directly.\n”, val);
- 如果该点入度不为0,且在无环图内,则直接将其路径输出
- 如果该点入度不为0,且在无环图内,则判断该点是否在Not_error[]数组,如果在则输出路径;否则输出Error
#include<iostream>
#include<vector>
#include<queue>
#include<cstring>
using namespace std;
typedef pair<int,int>PII;
const int N = 1E3 + 5, INF = 0x3f3f3f3f;
int n, m, q;
int S[N][N], D[N][N], query[N];
vector<int>vec[N];
int rd[N];
int topx[N], hh, tt = -1;
bool st[N], Not_error[N];
int dist[N], voucher[N], pre[N];
bool bfs(){
for(int i = 0; i < n; i ++ ){
if(rd[i] == 0) topx[++ tt] = i;
}
while(hh <= tt){
int tem = topx[hh ++];
for(auto it : vec[tem]){
rd[it] --;
if(!rd[it]) topx[++ tt] = it;
}
}
if(tt == n - 1) return true;
for(int i = 0; i <= tt; i ++ ) Not_error[topx[i]] = true;
return false;
}
void dijkstra(){
priority_queue<PII,vector<PII>,greater<PII>>heap;
memset(dist, 0x3f, sizeof dist);
memset(pre, -1, sizeof pre);
for(int i = 0; i < n; i ++ ){
if(rd[i] == 0){
dist[i] = 0;
heap.push({0, i});
}
}
while(!heap.empty()){
auto tem = heap.top();heap.pop();
int ver = tem.second, distance = tem.first;
if(st[ver]) continue;
st[ver] = true;
for(auto it : vec[ver]){
if(dist[it] > distance + S[ver][it]){
dist[it] = distance + S[ver][it];
voucher[it] = voucher[ver] + D[ver][it];
pre[it] = ver;
heap.push({dist[it], it});
}
else if(dist[it] == distance + S[ver][it]){
if(voucher[it] < voucher[ver] + D[ver][it]){
voucher[it] = voucher[ver] + D[ver][it];
pre[it] = ver;
}
}
}
}
}
int main(){
cin >> n >> m;
for(int i = 1; i <= m; i ++ ){
int a, b, c, d;
cin >> a >> b >> c >> d;
S[a][b] = c, D[a][b] = d;
vec[a].push_back(b);
rd[b] ++;
}
dijkstra();
cin >> q;
for(int i = 1; i <= q; i ++ ) cin >> query[i];
vector<int>v(rd, rd + n + 1);
bool flag = bfs();
printf("%s\n", flag == true ? "Okay." : "Impossible.");
for(int i = 1; i <= q; i ++ ){
int val = query[i];
if(!v[val]) printf("You may take test %d directly.\n", val);
else{
if(flag){
vector<int>res;
for(int i = val; i != -1; i = pre[i]) res.push_back(i);
for(int i = res.size() - 1; i >= 0; i -- ){
printf("%d%s", res[i], i == 0 ? "\n" : "->");
}
}
else{
if(Not_error[val]){
vector<int>res;
for(int i = val; i != -1; i = pre[i]) res.push_back(i);
for(int i = res.size() - 1; i >= 0; i -- ){
printf("%d%s", res[i], i == 0 ? "\n" : "->");
}
}
else printf("Error.\n");
}
}
}
return 0;
}
到了这里,关于PAT甲级图论相关题目的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!