Anna, Svyatoslav and Maps
You are given a directed unweighted graph without loops with n vertexes and a path in it (that path is not necessary simple) given by a sequence p1,p2,…,pm of m vertexes; for each 1≤i<m there is an arc from pi to pi+1.
Define the sequence v1,v2,…,vk of k vertexes as good, if v is a subsequence of p, v1=p1, vk=pm, and p is one of the shortest paths passing through the vertexes v1, …, vk in that order.
A sequence a is a subsequence of a sequence b if a can be obtained from b by deletion of several (possibly, zero or all) elements. It is obvious that the sequence p is good but your task is to find the shortest good subsequence.
If there are multiple shortest good subsequences, output any of them.
Input
The first line contains a single integer n (2≤n≤100) — the number of vertexes in a graph.
The next n lines define the graph by an adjacency matrix: the j-th character in the i-st line is equal to 1 if there is an arc from vertex i to the vertex j else it is equal to 0. It is guaranteed that the graph doesn’t contain loops.
The next line contains a single integer m (2≤m≤106) — the number of vertexes in the path.
The next line contains m integers p1,p2,…,pm (1≤pi≤n) — the sequence of vertexes in the path. It is guaranteed that for any 1≤i<m there is an arc from pi to pi+1.
Output
In the first line output a single integer k (2≤k≤m) — the length of the shortest good subsequence. In the second line output k integers v1, …, vk (1≤vi≤n) — the vertexes in the subsequence. If there are multiple shortest subsequences, print any. Any two consecutive numbers should be distinct.
Examples
input
4
0110
0010
0001
1000
4
1 2 3 4
output
3
1 2 4
input
4
0110
0010
1001
1000
20
1 2 3 4 1 2 3 4 1 2 3 4 1 2 3 4 1 2 3 4
output
11
1 2 4 2 4 2 4 2 4 2 4
input
3
011
101
110
7
1 2 3 1 3 2 1
output
7
1 2 3 1 3 2 1
input
4
0110
0001
0001
1000
3
1 2 4
output
2
1 4
分析:
先用floyd跑出各顶点间的最短路。
把p(1)加入答案,然后沿着题目给的路径序列遍历,
如果答案中的最后一个顶点到当前遍历到的顶点的最短距离
小于原序列中两点间的距离和,则答案加上p(i-1),并且继续遍历路径,
遍历完之后在最后加上p(m)
代码带注释
补充说明:
假设原序列为a,b,c,d
如果a->c的最短距离小于a->b+b->c,则b不能被删掉,因为删掉之后a->c的最短路径就不经过b了,
如果不能删,则答案序列最多只能到c的前面一个点也就是b,答案序列加上b,然后判断b->d
否则能删,如果能删就继续判断a->d
code:
#include<cstdio>
#include<cstring>
#include<iostream>
#include<vector>
#include<cmath>
#include<algorithm>
typedef long long ll;
const int inf=0x3f3f3f3f;
const int inn=0x80808080;
using namespace std;
const int maxm=105;
int g[maxm][maxm];
int p[maxm*maxm*maxm];
int ans[maxm*maxm*maxm],cnt;
int n,m;
void input(){
scanf("%d",&n);
getchar();
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
char t=getchar();
g[i][j]=(t=='1')?1:inf;
if(i==j)g[i][j]=0;//记得加这个
}
getchar();
}
scanf("%d",&m);
for(int i=1;i<=m;i++){
scanf("%d",&p[i]);
}
}
void floyd(){
for(int k=1;k<=n;k++){
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
g[i][j]=min(g[i][j],g[i][k]+g[k][j]);
}
}
}
}
void solve(){
ans[++cnt]=p[1];
int dis=0;//dis为当前点到答案最后一个点的距离
for(int i=2;i<=m;i++){
dis+=g[p[i-1]][p[i]];//累加
if(dis>g[ans[cnt]][p[i]]){//如果超过了答案序列最后一个点到当前点的最短距离
ans[++cnt]=p[i-1];//则把p[i-1]加入答案
dis=g[ans[cnt]][p[i]];//更新dis
}
}
ans[++cnt]=p[m];//记得加入p[m]
printf("%d\n",cnt);
for(int i=1;i<=cnt;i++){
printf("%d ",ans[i]);
}
}
int main(){
input();
floyd();
solve();
return 0;
}