With the ambition of conquering other spaces, he would like to visit all Doge Planets as soon as possible. More specifically, he would like to visit the Doge Planet x at the time no later than Deadline x. He also wants the sum of all arrival time of each Doge Planet to be as small as possible. You can assume it takes so little time to inspect his Doge Army that we can ignore it.
There are multiple test cases. Please process till EOF.
Each test case contains several lines. The first line of each test case contains one integer: n, as mentioned above, the number of Doge Planets. Then follow n lines, each contains n integers, where the y-th integer in the x-th line is T xy . Then follows a single line containing n - 1 integers: Deadline 2 to Deadline n.
All numbers are guaranteed to be non-negative integers smaller than or equal to one million. n is guaranteed to be no less than 3 and no more than 30.
If some Deadlines can not be fulfilled, please output “-1” (which means the Super Doge will say “WOW! So Slow! Such delay! Much Anger! . . . ” , but you do not need to output it), else output the minimum sum of all arrival time to each Doge Planet.
Sample Input
4 0 3 8 6 4 0 7 4 7 5 0 2 6 9 3 0 30 8 30 4 0 2 3 3 2 0 3 3 2 3 0 3 2 3 3 0 2 3 3Sample Output
36 -1题目的大意是说给个n乘n的矩阵D,Dxy表示从x到y的距离,然后从0开始移动,每个点都要经过,而且到达每个点的时间必须在限制范围内,且每个点可以重复到达,求走完所有点所需最短时间,如果在条件范围内无法走完所有点,就输出-1。
一开始拿到题目,想到的是bfs,当然,最小路径嘛,不过仔细想想就觉得不对,于是又多想了几遍,今天整个下午都在想这题,结果都没想出来,不过有段时间还是给我找到了头绪,就是先求出从一个点到另一个点的最小距离,(因为一开始给的并不是最小距离,有可能折返过后比直接到达还短)只是当时还缺点东西,于是依旧不能解决问题,即使后来用了一个十分暴力的方法也是TLE。
后来实在想不出解法时,我查到了求到每个点的最小距离的解法,而且很简单,如下:
for(int k=0;k<n;k++)
for(int i=0;i<n;i++)
for(int j=0;j<n;j++)
s[i][j]=min(s[i][j],s[i][k]+s[k][j]);
如果存在比直达还要短的路径,那么肯定存在一个只折一次到某点比直接到达该点的距离短,于是只要遍历就可以找到最短路径。
或者另一种理解思路:先选定一个点,再找另一个点,可以遍搜从这个点到另一个点再折到选定的点的所有情况,找到最小,再更换选定的点,再搜,可以遍历所有情况。
接下来就是直接的dfs了。
代码如下:
#include <stdio.h>
#include <iostream>
#include <cstring>
#include <stdlib.h>
#include <algorithm>
#include <queue>
#include <math.h>
#define MAX 35
#define INF 1e8
using namespace std;
int n;//n个数
int line[MAX];//到每个点的时间限制
int s[MAX][MAX];//输入的矩阵
int digi[MAX];//标记每个点是否走过,因为在找出最短路径之后,就等于没有了点可以重复走的条件了
int ans;//答案
void dfs(int a,int tim,int t)//现在的点a,现在的时间tim,前面到达各个点时间和t
{
int count1=0;
for (int i = 1;i < n;i++)
{
if(digi[i]==0)
count1++;
if(digi[i]==0&&tim>line[i])
return;
}//剪枝
if(count1&&t+tim*count1>ans)
return;
else if(!count1)
{
ans=min(t,ans);
}
for (int i=1;i<n;i++)
{
if(i!=a&&digi[i]==0&&tim+s[a][i]<=line[i])
{
digi[i]=1;
dfs(i,tim+s[a][i],t+tim+s[a][i]);
digi[i]=0;
}
}
}
int main(void)
{
while (scanf("%d",&n)!=EOF)
{
for (int i = 0;i < n;i++)
{
for (int j = 0;j < n;j++)
{
scanf("%d",&s[i][j]);
}
}
for(int k=0;k<n;k++)
for(int i=0;i<n;i++)
for(int j=0;j<n;j++)
s[i][j]=min(s[i][j],s[i][k]+s[k][j]);//找出一个点到各个点的最小值
for (int i = 1;i < n;i++)
scanf("%d",&line[i]);
ans=INF;
dfs(0,0,0);
if(ans==INF)
cout<<-1<<endl;
else
cout<<ans<<endl;
}
return 0;
}