图的遍历
A1013
本题考察是连通块的计算以及如何分割一个点。
本题需要知道增加最少的边使图联通的数为连通块的数量减1。
对于无权图最好使用邻接表,直接用vector数组即可。
- 用dfs方法,每次碰到分割点时就直接返回,最后计算调用了几次dfs函数就有几个连通块,而所求答案就是连通块数减1.
#include<bits/stdc++.h>
using namespace std;
const int N = 1010;
vector<int> G[N];
int n, m, k, currentPoint;
bool vis[N];
int father[N];
void dfs(int u)
{
if(u == currentPoint) return;
else
{
vis[u] = true;
for(int i = 0; i < G[u].size(); i++)
{
int v = G[u][i];
if(vis[v] == false) dfs(v);
}
}
}
int DFSTrave()
{
int num = 0;
for(int i = 1; i <= n; i++)
{
if(i == currentPoint) continue;
if(vis[i] == false)
{
dfs(i);
num++;
}
}
return num;
}
int main()
{
int u, v;
scanf("%d%d%d", &n, &m, &k);
for(int i = 0; i < m; i++)
{
scanf("%d%d", &u, &v);
G[u].push_back(v);
G[v].push_back(u);
}
while(k--)
{
memset(vis, false ,sizeof(vis));
scanf("%d", ¤tPoint);
printf("%d\n", DFSTrave() - 1);
}
return 0;
}
- 用并查集的方法,先将图读进去,读入隔离点后进行Union操作,如果u和v都不等于隔离点则将他们合并就相当于隔离了隔离点。最后记录总共读取了几个根节点就等于多少个连通块
#include<bits/stdc++.h>
using namespace std;
const int N = 1010;
vector<int> G[N];
int n, m, k, currentPoint;
bool vis[N];
int father[N];
void init()
{
for(int i = 0; i < n; i++)
{
father[i] = i;
vis[i] = false;
}
}
int findfather(int v)
{
if(father[v] == v) return v;
else
{
father[v] = findfather(father[v]);
return father[v];
}
}
void Union(int a, int b)
{
int fa = findfather(a);
int fb = findfather(b);
if(fa != fb) father[fa] = fb;
}
int main()
{
int u, v;
scanf("%d%d%d", &n, &m, &k);
for(int i = 0; i < m; i++)
{
scanf("%d%d", &u, &v);
G[u].push_back(v);
G[v].push_back(u);
}
while(k--)
{
init();
scanf("%d", ¤tPoint);
for(int u = 1; u <= n; u++)
{
for(int j = 0; j < G[u].size(); j++)
{
int v = G[u][j];
if(u != currentPoint && v != currentPoint)
{
Union(u, v);
}
}
}
int num = 0;
for(int i = 1; i <= n; i++)
{
if(i == currentPoint) continue;
int fa_i = findfather(i);
if(vis[fa_i] == false)
{
num++;
vis[fa_i] = true;
}
}
printf("%d\n", num - 1);
}
return 0;
}
A1021
所需数学知识:
- 求最深根结点集合时,对任意一个结点遍历得到的最深根结点集合一定属于所求集合
- 树的所有直径(最长深度的路路径)一定有公共区间或公共点
- 求最深根集合算法:先对任意结点进行遍历,得到最深根结合A,从A中任选一个集合再次遍历得到集合B。集合A和B的并即为所求
需要代码知识:
- 用并查集求连通分量
- 输出数组不重复元素
- dfs求最根节点集合
需要注意的点:
- block函数要赋初始值0
- 记得调用init函数来初始化并查集
- dfs中temp更新,ans在主函数跟新
- 因为是无向图在邻接表遍历的时候可能会出现遇到前驱的情况,所以要加入一个参数pre,跳过pre的情况
#include<bits/stdc++.h>
using namespace std;
const int N = 100010;
int n, maxdepth;
vector<int> G[N];
vector<int> temp, ans;
int father[N];
bool isroot[N];
void init()
{
for(int i = 1; i <= n; i++)
{
father[i] = i;
isroot[i] = false;
}
}
int findfather(int x)
{
int a = x;
while(x != father[x])
x = father[x];
while(a != father[a])
{
int z = a;
a = father[a];
father[z] = x;
}
return x;
}
void Union(int a, int b)
{
int fa = findfather(a);
int fb = findfather(b);
if(fa != fb) father[fa] = fb;
}
int callblock()
{
int block = 0;
for(int i = 1; i <= n; i++)
{
isroot[findfather(i)] = true;
}
for(int i = 1; i <= n; i++)
block+=isroot[i];
return block;
}
void DFS(int u, int depth, int pre)
{
if(depth > maxdepth)
{
maxdepth = depth;
temp.clear();
temp.push_back(u);
}
else if(depth == maxdepth)
{
temp.push_back(u);
}
for(int i = 0; i < G[u].size(); i++)
{
int v = G[u][i];
if(v == pre) continue;
DFS(v, depth+1, u);
}
}
int main()
{
scanf("%d", &n);
init();
for(int i = 1; i < n; i++)
{
int a, b;
scanf("%d%d", &a, &b);
G[a].push_back(b);
G[b].push_back(a);
Union(a, b);
}
int block = callblock();
if(block != 1) printf("Error: %d components", block);
else
{
DFS(1, 1, -1);
ans = temp;
DFS(ans[0], 1, -1);
for(int i = 0; i < temp.size(); i++)
{
ans.push_back(temp[i]);
}
sort(ans.begin(), ans.end());
printf("%d\n", ans[0]);
for(int i = 1; i < ans.size(); i++)
{
if(ans[i] != ans[i - 1]) printf("%d\n", ans[i]);
}
}
return 0;
}
A1034
本题也是dfs遍历题目,但是需要处理字符串,首先需要建立字符串与数字的映射。在dfs中对每个结点访问时先判断是否成为head再对每条边进行访问,为了方式重复将边计算的情况每次将边加入后都要把边的权值设为0。最后建立map将结果存储。
需要注意n最大为2010,因为可能出现每个通话人都不一样的情况,所以要2*N。
#include<bits/stdc++.h>
using namespace std;
const int N = 2010;
int G[N][N];
int weight[N];
bool vis[N];
map<string,int> string2int;
map<int,string> int2string;
map<string,int> gang;
int n, k, numperson = 0;
int change(string str)
{
if(string2int.find(str) != string2int.end())
return string2int[str];
else
{
string2int[str] = numperson;
int2string[numperson] = str;
return numperson++;
}
}
void DFS(int nowvisit, int& head, int& number, int& totalvalue)
{
if(weight[nowvisit] > weight[head])
head = nowvisit;
number++;
vis[nowvisit] = true;
for(int i = 0; i < n; i++)
{
if(G[nowvisit][i] > 0)
{
totalvalue+=G[nowvisit][i];
G[nowvisit][i] = G[i][nowvisit] = 0;
if(vis[i] == false)
{
DFS(i, head, number, totalvalue);
}
}
}
}
int main()
{
scanf("%d%d", &n, &k);
string str1, str2;
int value;
for(int i = 0; i < n; i++)
{
cin >> str1 >> str2 >> value;
int id1 = change(str1);
int id2 = change(str2);
weight[id1] += value;
weight[id2] += value;
G[id1][id2] += value;
G[id2][id1] += value;
}
for(int i = 0; i < numperson; i++)
{
if(vis[i] == false)
{
int head = i, number = 0, totalvalue = 0;
DFS(i, head, number, totalvalue);
if(totalvalue > k && number > 2)
{
gang[int2string[head]] = number;
}
}
}
printf("%d\n", gang.size());
map<string,int>::iterator it;
for(it = gang.begin(); it != gang.end(); it++)
{
cout << it->first << " " << it->second << endl;
}
return 0;
}
A1076
一道带层数的bfs题,注意num是统计可以转发的数目,第一个不算,需要加入队列时num++。
#include<bits/stdc++.h>
using namespace std;
const int N = 1010;
struct node
{
int v, layer;
};
vector<node> G[N];
bool inq[N] = {false};
int n, l;
int BFS(int s, int l)
{
int num = 0;
queue<node> q;
node start;
start.v = s;
start.layer = 0;
q.push(start);
inq[start.v] = true;
while(!q.empty())
{
node topNode = q.front();
q.pop();
int u = topNode.v;
for(int i = 0; i < G[u].size(); i++)
{
node temp = G[u][i];
temp.layer = topNode.layer + 1;
if(inq[temp.v] == false && temp.layer <= l)
{
q.push(temp);
num++;
inq[temp.v] = true;
}
}
}
return num;
}
int main()
{
int followNum, idfollow;
node user;
scanf("%d%d", &n, &l);
for(int i = 1; i <= n; i++)
{
scanf("%d", &followNum);
for(int j = 0; j < followNum; j++)
{
user.v = i;
scanf("%d", &idfollow);
G[idfollow].push_back(user);
}
}
int query, s;
scanf("%d", &query);
for(int i = 0; i < query; i++)
{
scanf("%d", &s);
memset(inq, false, sizeof(inq));
printf("%d\n", BFS(s, l));
}
return 0;
}
最短路径
A1003
本题要求最短路径的个数以及最多权值数,是一道模板题,用了dijkstra堆优化+dfs完成
#include<bits/stdc++.h>
using namespace std;
const int N = 510;
const int inf = 0x3fffffff;
struct node
{
int v, dis;
node(int _v, int _dis):v(_v),dis(_dis){}
friend bool operator < (const node& a, const node& b)
{
return a.dis > b.dis;
}
};
vector<node> Adj[N];
bool vis[N];
int dist[N];
int weight[N];
vector<int> pathtemp, path;
vector<int> pre[N];
int n, m, c1, c2;
void dijkstra(int st)
{
fill(dist,dist+N, inf);
memset(vis, false, sizeof(vis));
dist[st] = 0;
priority_queue<node> q;
q.push(node(st, 0));
//vis[st] = true;
while(!q.empty())
{
node temp = q.top();
q.pop();
int u = temp.v;
if(vis[u]) continue;
vis[u] = true;
for(int i = 0; i < Adj[u].size(); i++)
{
int v = Adj[u][i].v;
int dis = Adj[u][i].dis;
if(vis[v] == false)
{
if(dist[v] > dist[u] + dis)
{
dist[v] = dist[u] + dis;
pre[v].clear();
pre[v].push_back(u);
q.push(node(v,dist[v]));
}
else if(dist[v] == dist[u] + dis)
{
pre[v].push_back(u);
}
}
}
}
}
int num = 0, maxpeople = 0;
void dfs(int s, int v)
{
if(s == v)
{
num++;
pathtemp.push_back(s);
int people = 0;
for(int i = 0; i < pathtemp.size(); i++)
{
people += weight[pathtemp[i]];
}
if(people > maxpeople)
{
maxpeople = people;
path = pathtemp;
}
pathtemp.pop_back();
return ;
}
pathtemp.push_back(v);
for(int i = 0; i < pre[v].size(); i++)
dfs(s, pre[v][i]);
pathtemp.pop_back();
}
int main()
{
cin >> n >> m >> c1 >> c2;
for(int i = 0; i < n; i++)
{
scanf("%d", &weight[i]);
}
int u, v, dis;
for(int i = 0; i < m; i++)
{
scanf("%d%d%d", &u, &v, &dis);
Adj[u].push_back(node(v,dis));
Adj[v].push_back(node(u,dis));
}
dijkstra(c1);
dfs(c1, c2);
printf("%d %d", num, maxpeople);
return 0;
}
A1018
典型的找最短路径问题,只不过在处理path数组时需要一个结点一个结点的判断。
不能把最短路径求出后直接求总数量,因为可能会出现先要取一部分车,但是后面车太多又要带回去的情况。
需要在获得最短路径后在dfs里面对每个一个结点进行更新need和back,所以需要一个remain来记录当前有多少辆。
小技巧是在读入结点权值后可以让每个权值减去capacit/2,这样结点权值的正负就代表需要车还是留有车辆。
#include<bits/stdc++.h>
using namespace std;
const int N = 510;
const int INF = 0x3fffffff;
struct node
{
int v, dis;
node(int _v, int _dis) : v(_v), dis(_dis){}
};
int c, n, m, idex;
vector<node> Adj[N];
int weight[N];
int dist[N], num[N];
bool inq[N];
vector<int> pre[N];
vector<int> pathtemp, path;
void spfa()
{
fill(dist, dist + N, INF);
memset(inq, false, sizeof(inq));
queue<int> q;
q.push(0);
inq[0] = true;
num[0]++;
dist[0] = 0;
while(!q.empty())
{
int u = q.front();
q.pop();
inq[u] = false;
for(int j = 0; j < Adj[u].size(); j++)
{
int v = Adj[u][j].v;
int dis = Adj[u][j].dis;
if(dist[v] > dist[u] + dis)
{
dist[v] = dist[u] + dis;
pre[v].clear();
pre[v].push_back(u);
if(inq[v] == false)
{
q.push(v);
inq[v] = true;
num[v]++;
if(num[v] >= n) return ;
}
}
else if(dist[v] == dist[u] + dis)
{
pre[v].push_back(u);
}
}
}
}
int minneed = INF, minback = INF;
void dfs(int v)
{
if(v == 0)
{
int need = 0, back = INF, remain = 0;
for(int i = pathtemp.size() - 1; i >= 0; i--)
{
if(remain >= abs(weight[pathtemp[i]]))
{
remain += weight[pathtemp[i]];
}
else
{
if(weight[pathtemp[i]] < 0)
{
need += ( abs(weight[pathtemp[i]]) - remain);
remain = 0;
}
else
remain += weight[pathtemp[i]];
}
back = remain;
}
if(minneed > need)
{
minneed = need;
minback = back;
path = pathtemp;
}
else if(minneed == need)
{
if(minback > back)
{
minback = back;
path = pathtemp;
}
}
return ;
}
pathtemp.push_back(v);
for(int i = 0; i < pre[v].size(); i++)
dfs(pre[v][i]);
pathtemp.pop_back();
}
int main()
{
scanf("%d%d%d%d", &c, &n, &idex, &m);
c /= 2;
for(int i = 1; i <= n; i++)
{
scanf("%d", &weight[i]);
weight[i] -= c;
}
int u, v, d;
for(int i = 0; i < m; i++)
{
scanf("%d%d%d", &u, &v, &d);
Adj[u].push_back(node(v, d));
Adj[v].push_back(node(u, d));
}
spfa();
dfs(idex);
printf("%d 0->", minneed);
for(int i = path.size() - 1; i >= 0; i--)
{
printf("%d", path[i]);
if(i != 0) printf("->");
}
printf(" %d", minback);
return 0;
}
dijkstra堆优化版本+dfs
#include<bits/stdc++.h>
using namespace std;
const int N = 510;
const int inf = 0x3fffffff;
int c, n, m, sp;
int weight[N];
struct node
{
int v, dis;
node(int _v, int _dis):v(_v), dis(_dis){}
friend bool operator<(const node& a, const node& b)
{
return a.dis > b.dis;
}
};
vector<node> Adj[N];
vector<int> pre[N];
vector<int> path, pathtemp;
bool vis[N];
int dist[N];
void dijkstra(int st)
{
fill(dist,dist+N, inf);
memset(vis, false, sizeof(vis));
dist[st] = 0;
priority_queue<node> q;
q.push(node(st, 0));
while(!q.empty())
{
node temp = q.top();
q.pop();
int u = temp.v;
if(vis[u]) continue;
vis[u] = true;
for(int i = 0; i < Adj[u].size(); i++)
{
int v = Adj[u][i].v;
int dis = Adj[u][i].dis;
if(vis[v] == false)
{
if(dist[v] > dist[u] + dis)
{
dist[v] = dist[u] + dis;
pre[v].clear();
pre[v].push_back(u);
q.push(node(v,dist[v]));
}
else if(dist[v] == dist[u] + dis)
{
pre[v].push_back(u);
}
}
}
}
}
int minneed = inf, minback = inf;
void dfs(int s, int v)
{
if(s == v)
{
pathtemp.push_back(v);
int remain = 0, need = 0, back = 0;
for(int i = pathtemp.size()-1; i>= 0; i--)
{
if(remain < abs(weight[pathtemp[i]]))
{
if(weight[pathtemp[i]] > 0)
{
remain += weight[pathtemp[i]];
}
else
{
need += (abs(weight[pathtemp[i]]) - remain);
remain = 0;
}
}
else
{
remain += weight[pathtemp[i]];
}
}
back = remain;
if(need < minneed)
{
minneed = need;
minback = back;
path = pathtemp;
}
else if(need = minneed && back < minback)
{
minback = back;
path = pathtemp;
}
pathtemp.pop_back();
return ;
}
pathtemp.push_back(v);
for(int i = 0; i < pre[v].size(); i++)
dfs(s, pre[v][i]);
pathtemp.pop_back();
}
int main()
{
cin >> c >> n >> sp >> m;
c /= 2;
for(int i = 1; i <= n; i++)
{
scanf("%d", &weight[i]);
weight[i] -= c;
}
int u, v, dis;
for(int i = 0; i < m; i++)
{
scanf("%d%d%d", &u, &v, &dis);
Adj[u].push_back(node(v,dis));
Adj[v].push_back(node(u,dis));
}
dijkstra(0);
dfs(0, sp);
printf("%d ", minneed);
for(int i = path.size() -1; i > 0; i--)
printf("%d->", path[i]);
printf("%d %d", path[0], minback);
return 0;
}
A1030
SPFA算法
#include<bits/stdc++.h>
using namespace std;
const int INF = 0x3fffffff;
const int N = 510;
struct node
{
int v, cost, dis;
node(int _v, int _dis): v(_v), dis(_dis) {}
};
int cost[N][N];
vector<node> Adj[N];
int n, m, st, ed;
int dist[N];
bool inq[N];
int num[N];
set<int> pre[N];
vector<int> path, pathtemp;
void SPFA(int s)
{
fill(dist, dist+N, INF);
memset(num, 0, sizeof(num));
memset(inq, false, sizeof(inq));
queue<int> q;
q.push(s);
inq[s] = true;
num[s]++;
dist[s] = 0;
while(!q.empty())
{
int u = q.front();
q.pop();
inq[u] = false;
for(int j = 0; j < Adj[u].size(); j++)
{
int v = Adj[u][j].v;
int dis = Adj[u][j].dis;
if(dist[v] > dist[u] + dis)
{
dist[v] = dist[u] + dis;
pre[v].clear();
pre[v].insert(u);
if(inq[v] == false)
{
q.push(v);
inq[v] = true;
num[v]++;
if(num[v] >= n) return;
}
}
else if(dist[v] == dist[u] + dis)
{
pre[v].insert(u);
}
}
}
}
int mincost = INF;
void dfs(int s, int v)
{
if(s == v)
{
int c = 0;
pathtemp.push_back(s);
for(int i = pathtemp.size() - 1; i > 0; i--)
{
int id = pathtemp[i], idnext = pathtemp[i-1];
c += cost[id][idnext];
}
if(c < mincost)
{
path = pathtemp;
mincost = c;
}
pathtemp.pop_back();
return ;
}
pathtemp.push_back(v);
for(set<int>::iterator it = pre[v].begin(); it != pre[v].end(); it++)
dfs(s,*it);
pathtemp.pop_back();
}
int main()
{
//fill(G[0], G[0] + N*N, INF);
fill(cost[0], cost[0]+N*N, INF);
scanf("%d%d%d%d", &n, &m, &st, &ed);
int u, v, d, co;
for(int i = 0; i < m; i++)
{
scanf("%d%d%d%d", &u, &v, &d, &co);
Adj[u].push_back(node(v, d));
Adj[v].push_back(node(u, d));
cost[u][v] = cost[v][u] = co;
}
SPFA(st);
dfs(st, ed);
for(int i = path.size() - 1; i >= 0; i--)
cout << path[i] <<" ";
printf("%d %d", dist[ed], mincost);
return 0;
}
朴素dijkstra+dfs版本
#include<bits/stdc++.h>
using namespace std;
const int N = 510;
const int inf = 0x3fffffff;
int n, m, s, d;
int G[N][N], cost[N][N];
int dist[N];
bool vis[N];
vector<int> pre[N];
vector<int> path, pathtemp;
void dijkstra(int s)
{
fill(dist, dist + N, inf);
memset(vis, false, sizeof(vis));
dist[s] = 0;
for(int i = 0; i < n; i++)
{
int u = -1, MIN = inf;
for(int j = 0; j < n; j++)
{
if(vis[j] == false && dist[j] < MIN)
{
u = j;
MIN = dist[j];
}
}
if(u == -1) return;
vis[u] = true;
for(int v = 0; v < n; v++)
{
if(G[u][v] != inf && vis[v] == false)
{
if(dist[v] > dist[u] + G[u][v])
{
dist[v] = dist[u] + G[u][v];
pre[v].clear();
pre[v].push_back(u);
}
else if(dist[v] == dist[u] + G[u][v])
{
pre[v].push_back(u);
}
}
}
}
}
int mincost = inf;
void dfs(int s, int v)
{
if(s == v)
{
pathtemp.push_back(v);
int c = 0;
for(int i = pathtemp.size() - 1; i > 0; i--)
{
int id = pathtemp[i-1], idnext = pathtemp[i];
c += cost[id][idnext];
}
if(c < mincost)
{
mincost = c;
path = pathtemp;
}
pathtemp.pop_back();
return ;
}
pathtemp.push_back(v);
for(int i = 0; i < pre[v].size(); i++)
{
dfs(s, pre[v][i]);
}
pathtemp.pop_back();
}
int main()
{
fill(G[0], G[0]+N*N, inf);
int u, v, dis, co;
scanf("%d%d%d%d", &n, &m, &s, &d);
for(int i = 0; i < m; i++)
{
scanf("%d%d%d%d", &u, &v, &dis, &co);
if(G[u][v] > dis)
{
G[u][v] = G[v][u] = dis;
cost[u][v] = cost[v][u] = co;
}
}
dijkstra(s);
dfs(s, d);
for(int i = path.size() - 1; i >= 0; i--)
printf("%d ", path[i]);
printf("%d %d", dist[d], mincost);
return 0;
}
A1072
本题也是dfs题目,只不过需要考虑的不是最短路径,而是先记录所有dist数组然后再dfs中计算最短平均距离和最大的最近距离。需要注意的是如何将字符串转换为数字。
几个坑点
1.输出的数据可能重复,比如同两个点有多个路径则选择最小的路,所以在输入时需要判定。
2.如果给定两个相同的点,所以需要先讲g[i][i]置为0
3.学会如何保留有效数字
#include<bits/stdc++.h>
using namespace std;
const int N = 510;
const int inf = 0x3fffffff;
int n, m, s, d;
int G[N][N], cost[N][N];
int dist[N];
bool vis[N];
vector<int> pre[N];
vector<int> path, pathtemp;
void dijkstra(int s)
{
fill(dist, dist + N, inf);
memset(vis, false, sizeof(vis));
dist[s] = 0;
for(int i = 0; i < n; i++)
{
int u = -1, MIN = inf;
for(int j = 0; j < n; j++)
{
if(vis[j] == false && dist[j] < MIN)
{
u = j;
MIN = dist[j];
}
}
if(u == -1) return;
vis[u] = true;
for(int v = 0; v < n; v++)
{
if(G[u][v] != inf && vis[v] == false)
{
if(dist[v] > dist[u] + G[u][v])
{
dist[v] = dist[u] + G[u][v];
pre[v].clear();
pre[v].push_back(u);
}
else if(dist[v] == dist[u] + G[u][v])
{
pre[v].push_back(u);
}
}
}
}
}
int mincost = inf;
void dfs(int s, int v)
{
if(s == v)
{
pathtemp.push_back(v);
int c = 0;
for(int i = pathtemp.size() - 1; i > 0; i--)
{
int id = pathtemp[i-1], idnext = pathtemp[i];
c += cost[id][idnext];
}
if(c < mincost)
{
mincost = c;
path = pathtemp;
}
pathtemp.pop_back();
return ;
}
pathtemp.push_back(v);
for(int i = 0; i < pre[v].size(); i++)
{
dfs(s, pre[v][i]);
}
pathtemp.pop_back();
}
int main()
{
fill(G[0], G[0]+N*N, inf);
int u, v, dis, co;
scanf("%d%d%d%d", &n, &m, &s, &d);
for(int i = 0; i < m; i++)
{
scanf("%d%d%d%d", &u, &v, &dis, &co);
if(G[u][v] > dis)
{
G[u][v] = G[v][u] = dis;
cost[u][v] = cost[v][u] = co;
}
}
dijkstra(s);
dfs(s, d);
for(int i = path.size() - 1; i >= 0; i--)
printf("%d ", path[i]);
printf("%d %d", dist[d], mincost);
return 0;
}
A1087
前面几道题的结合,既要把字符串转换成数字,也要多重判断用dijkstra+dfs解决。
#include<bits/stdc++.h>
using namespace std;
const int N = 220;
const int inf = 0x3fffffff;
map<string, int> string2int;
map<int, string> int2string;
vector<int> pre[N];
vector<int> path, pathtemp;
int numperson = 1;
int weight[N];
int G[N][N];
int n, k;
int change(string str)
{
if(string2int.find(str) != string2int.end())
return string2int[str];
else
{
string2int[str] = numperson;
int2string[numperson] = str;
return numperson++;
}
}
bool vis[N];
int dist[N];
void dijkstra(int s)
{
fill(dist, dist+N, inf);
fill(vis, vis+N, false);
dist[s] = 0;
for(int i = 0; i < n; i++)
{
int u = -1, MIN = inf;
for(int j = 0; j < n; j++)
{
if(vis[j] == false && dist[j] < MIN)
{
u = j;
MIN = dist[j];
}
}
if(u == -1) return;
vis[u] = true;
for(int v = 0; v < n; v++)
{
if(vis[v] == false && G[u][v] != inf)
{
if(dist[v] > dist[u] + G[u][v])
{
dist[v] = dist[u] + G[u][v];
pre[v].clear();
pre[v].push_back(u);
}
else if(dist[v] == dist[u] + G[u][v])
{
pre[v].push_back(u);
}
}
}
}
}
int maxhap = 0, maxavg = 0, num = 0;;
void dfs(int s, int v)
{
if(s == v)
{
num++;
pathtemp.push_back(v);
int hap = 0, avg = 0, len = pathtemp.size();
for(int i = 0; i < len; i++)
{
hap += weight[pathtemp[i]];
}
avg = hap / (pathtemp.size() - 1);
if(hap > maxhap)
{
maxhap = hap;
maxavg = avg;
path = pathtemp;
}
else if(hap == maxhap && avg > maxavg)
{
maxavg = avg;
path = pathtemp;
}
pathtemp.pop_back();
return ;
}
pathtemp.push_back(v);
for(int i = 0; i < pre[v].size(); i++)
{
dfs(s,pre[v][i]);
}
pathtemp.pop_back();
}
int main()
{
fill(G[0], G[0] +N*N, inf);
string2int["ROM"] = 0;
int2string[0] = "ROM";
string c1, c2;
cin >> n >> k >> c1;
int st = change(c1);
int id, w;
for(int i = 0; i < n - 1; i++)
{
cin >> c1 >> w;
id = change(c1);
weight[id] += w;
}
int u, v, dis;
for(int i = 0; i < k; i++)
{
cin >> c1 >> c2 >> dis;
u = change(c1);
v = change(c2);
G[u][v] = G[v][u] = dis;
}
dijkstra(st);
dfs(st, 0);
printf("%d %d %d %d\n", num, dist[0], maxhap, maxavg);
for(int i = path.size() - 1; i >= 0; i--)
{
cout << int2string[path[i]];
if(i != 0) printf("->");
}
return 0;
}