题目链接:http://codeforces.com/contest/1204/problem/C
题目大意:给你一张邻接矩阵的图,和一个序列p,让你找到有个最短的p的子序列q。
要求在图上依次访问q最短路,能经过p的所有节点。
我们考虑压缩一些节点。无用的信息。
p[1]和p[m]一定是确定的。
那么对于节点p[i]。假设上一个确定的节点为u。如果p[i]在u到p[i+1]的最短路上(dis[u][p[i]]] + dis[p[i-1]][p[i+1]] == dis[u][p[i+1]]),那么p[i]是可以压缩的。
否则这个点不可以压缩,成为一个新的确定点。
#include <bits/stdc++.h>
#define fast ios::sync_with_stdio(false), cin.tie(0), cout.tie(0)
#define N 105
#define M 1000005
#define INF 0x3f3f3f3f
#define mk(x) (1<<x) // be conscious if mask x exceeds int
#define sz(x) ((int)x.size())
#define lson(x) (x<<1)
#define rson(x) (x<<1|1)
#define mp(a,b) make_pair(a, b)
#define endl '\n'
#define lowbit(x) (x&-x)
using namespace std;
typedef long long ll;
typedef double db;
/** fast read **/
template <typename T>
inline void read(T &x) {
x = 0; T fg = 1; char ch = getchar();
while (!isdigit(ch)) {
if (ch == '-') fg = -1;
ch = getchar();
}
while (isdigit(ch)) x = x*10+ch-'0', ch = getchar();
x = fg * x;
}
template <typename T, typename... Args>
inline void read(T &x, Args &... args) { read(x), read(args...); }
int n, m;
int a[N][N];
bool cant[N][N];
int p[M];
void Folyd() {
memset(cant, false, sizeof cant);
for (int k = 1; k <= n; k++) {
for (int i = 1; i <= n; i++) if (i != k) {
for (int j = 1; j <= n; j++) if (j != i && j != k) {
if (a[i][j] > a[i][k] + a[k][j])
a[i][j] = a[i][k] + a[k][j];
else if (a[i][j] == a[i][k] + a[k][j]) {
cant[i][j] = true;
}
}
}
}
}
vector <int> ans;
int main()
{
read(n);
for (int i = 1; i <= n; i++) {
string s; cin >> s;
for (int j = 1; j <= n; j++) {
if (j == i)
a[i][j] = 0;
else if (s[j-1] == '1')
a[i][j] = 1;
else
a[i][j] = 1e5;
}
}
read(m);
for (int i = 1; i <= m; i++) {
read(p[i]);
}
Folyd();
int u = p[1];
ans.push_back(u);
for (int i = 2; i <= m; i++) {
if (a[u][p[i]] == a[u][p[i-1]]+a[p[i-1]][p[i]])
continue;
u = p[i-1];
ans.push_back(u);
}
ans.push_back(p[m]);
cout << ans.size() << endl;
for (int i = 0; i < sz(ans); i++) {
printf("%d%c", ans[i], i == sz(ans)-1 ? '\n' : ' ');
}
return 0;
}