题意:有n个星球,我从第0个星球出发,后n-1个星球都有死期,我要争取在他们毁灭之前将他们都拜访一次,如果我能成功,输出我到达每个星球的时间的和(不是拜访完的最短用时),不能成功则输出-1。
思路:用dfs然后剪枝。
#include
#include
int n, dist[40][40], vis[40], deadline[40], summin;
void dfs(int v, int left ,int prevtime, int sum)
{
int i;
if(left == 0)
{//所有星球都拜访过了,summin有可能改变,将当前到各个星球的用时之和sum与之前确定的用时之和summin比较
if(sum < summin) summin = sum;
return ;
}
for(i = 1; i < n; i++)
{//如果在当前已用时间prevtime的情况下无法在某星球毁灭前到达该星球,summin值不会改变,剪枝
if(vis[i] != 1 && prevtime + dist[v][i] > deadline[i])
{
return ;
}
}
for(i = 1; i < n; i++)
if( vis[i] != 1 &&(sum + dist[v][i]) < summin)
{//当前到各个星球的用时之和sum小于summin,summin才可能改变,需要继续搜索
vis[i] = 1;
dfs(i, left - 1, prevtime + dist[v][i], sum + left * dist[v][i]);
vis[i] = 0;
}
}
void floyd()
{
int k, i, j;
for(k = 0; k < n; k++)
for(i = 0; i < n; i++)
for(j = 0; j < n; j++)
{
if(dist[i][j] > dist[i][k] + dist[k][j])
//如果考虑经过k点后,从i经过k到j的距离 比 从i只能经过前面k-1个点到j距离短,更新从i到j的最短距离
dist[i][j] = dist[i][k] + dist[k][j];
}
}
int main()
{
#ifdef LOCAL
freopen("data.in", "r" ,stdin);
#endif
int time, i, j;
while(scanf("%d", &n) != EOF)
{
summin = 1000000;
memset(vis, 0, sizeof(vis));
for(i = 0; i < n; i++)
for(j = 0; j < n; j++)
scanf("%d", &dist[i][j]);
for(i = 1; i < n; i++)
scanf("%d", &deadline[i]);
floyd();//求两点间的最短路径长度
vis[0] = 1;
dfs (0, n - 1, 0, 0);
if(summin < 1000000)printf("%d\n", summin);
else printf("-1\n");
}
return 0;
}