#include<bits/stdc++.h>
using namespace std;
const int INF = 1e9;
int n, m, k, r[55], d, dis[55][55], csl[55], ans, len;
double t, t_delta = 0.95;
bool c[55];
int calc()
{
int res = -1, minn = INT_MAX;
for (int i = 1; i <= k; i++)
c[csl[i]] = true;
for (int i = 0; i < n; i++)
{
if (!c[i])
{
minn = INT_MAX;
for (int j = 0; j < n; j++)
if (i != j && c[j])
minn = min(minn, dis[i][j]);
res = max(res, minn);
}
}
for (int i = 1; i <= k; i++)
c[csl[i]] = false;
return res;
}
void SA()
{
t = 5000;
while (t > 1e-10)
{
int i = rand() % k + 1;
int j = rand() % (len - k) + 1;
swap(csl[i], csl[j]);
int energy = calc();
int delta = energy - ans;
if (delta < 0)
ans = energy;
else if (exp(-delta / t) * RAND_MAX < rand())
swap(csl[i], csl[j]);
t *= t_delta;
}
}
void solve()
{
ans = calc();
if (m + k == n)
{
cout << 0;
exit(0);
}
for (int i = 1; i <= 100; i++)
SA();
}
int main()
{
srand(12345678);
srand(rand());
cin >> n >> m >> k;
for (int i = 0; i < n; i++)
cin >> r[i];
for (int i = 0; i < n; i++)
{
cin >> d;
if (!dis[i][r[i]])
{
dis[r[i]][i] = d;
dis[i][r[i]] = d;
}
}
for (int i = 1; i <= m; i++)
{
cin >> d;
c[d] = i;
}
for (int i = 0; i < n; i++)
for (int j = 0; j < n; j++)
{
if (i != j && dis[i][j] == 0)
dis[i][j] = INF;
if (i == j)
dis[i][j] = 0;
}
for (int i = 0; i < n; i++)
for (int j = 0; j < n; j++)
if (i != j)
for (int k = 0; k < n; k++)
if (k != i && k != j)
dis[i][j] = min(dis[i][j], dis[i][k] + dis[k][j]);
for (int i = 0; i < n; i++)
if (!c[i])
csl[++len] = i;
solve();
cout << ans;
}
思路就是先用 Floyd 处理各个点之间的最短路 然后模拟退火
c数组存的是已经放的城堡 csl数组存的是没放的