版权声明:转载请注明出处 https://blog.csdn.net/jay__bryant/article/details/81807428
题意:给定n个星球(编号1~n, n<=30),和从每个星球到达每个星球的时间,再给定到达每个星球的截止时间。从星球1出发,遍历2~n个星球,求每个星球的到达时间的总和。PS:每个星球可能不止经过一次!!!
dis[i][j]:i到j的最短距离,由floyd预处理
time[i]:到达i星球的时间,初始化-1。ans = sigma(time[i]) (2<=i<=n)
剪枝1:以达到当前点u的时间作为剩余点的到达时间(肯定小于搜下去的答案),
若还是大于了当前最优解,则没必要搜下去。
剪枝2:从当前点出发,只要有一个还未到达的点的到达时间大于dl则return;
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int INF = 0x3f3f3f3f;
const int N = 35;
int time[N], ans;//time[i]:到达i的时间
int dl[N], dis[N][N];
int n;
void dfs(int u, int m, int ret)//当前点u,已经到达了m个点,当前总时间ret
{
if(m==n)//如果到达了所有点,则更新答案
{
ans = min(ans, ret);
return;
}
if(ret+time[u]*(n-m)>ans)//剪枝:以达到当前点u的时间作为剩余点的到达时间(肯定小于搜下去的答案)
return; //若还是大于了当前最优解,则没必要搜下去
for(int i = 2; i <= n; ++i)//剪枝:从当前点出发,只要有一个还未到达的点的到达时间大于dl则return;
if(time[i]==-1 && time[u]+dis[u][i]>dl[i])
return;
for(int i = 2; i <= n; ++i)
if(time[i]==-1)
{
time[i] = time[u]+dis[u][i];
dfs(i, m+1, ret+time[i]);
time[i] = -1;
}
}
int main()
{
while(~scanf("%d", &n))
{
for(int i = 1; i <= n; ++i)
for(int j = 1; j <= n; ++j)
scanf("%d", &dis[i][j]);
for(int k = 1; k <= n; ++k)
for(int i = 1; i <= n; ++i)
for(int j = 1; j <= n; ++j)
dis[i][j] = min(dis[i][j], dis[i][k]+dis[k][j]);
for(int i = 2; i <= n; ++i) scanf("%d", &dl[i]);
memset(time, -1, sizeof(time));
time[1] = 0;
ans = INF;
dfs(1, 1, 0);
if(ans==INF) printf("-1\n");
else printf("%lld\n", ans);
}
return 0;
}