题意:n个点,告诉两两点之间的距离,然后求从1开始到其它所有的点的距离的和。
每一个点有一个时间底线,只有不超过时间底线才有可能到达此点否则无法到达。
输出距离和的最小值。
想法:因为有两两点之间的距离,所以可以枚举这个人到达所有点的顺序。有两个剪枝:1.如果当前时刻要到达k点,那么k点的时间底线一定要大于等于当前时刻+map[now][k]。
2.让总时间先走一步。因为时间是累加的,类似于:
1
1+2
1+2+3
1+2+3+4
............
1+2+3+4+5+...+n
显然可以发现1被加了n次,2被加了n-1次,以此类推k被加了n-(k-1)次,所以在计算总时间的时候可以采用这种方法,让总时间先行一步,如果此时的总时间大于已有的总时间答案的话,那么写下来的数都不用再去枚举了。
#include<iostream> #include<cstdio> #include<cstring> #define inf 0x7ffffff using namespace std; int n,ans; int map[35][35],dl[35],maxdl; int vis[35]; void floyd() { for(int k=1;k<=n;k++) { for(int i=1;i<=n;i++) { for(int j=1;j<=n;j++) { if(map[i][j]>map[i][k]+map[k][j]) { map[i][j]=map[i][k]+map[k][j]; } } } } } void dfs(int pos,int hasnum,int tim,int kk,int sumtim) { if(tim>maxdl) return; if(tim>dl[pos]) return; if(sumtim>ans) return;//很重要 for(int i=2;i<=n;i++) { if(!vis[i]&&tim+map[pos][i]>dl[i]) return; } if(hasnum==n) { if(sumtim<ans) ans=sumtim; return; } for(int i=2;i<=n;i++) { if(vis[i]) continue; vis[i]=1; dfs(i,hasnum+1,tim+map[pos][i],kk-1,sumtim+map[pos][i]*kk);//sumtim预处理了很多组数据 vis[i]=0; } } int main() { while(~scanf("%d",&n)) { for(int i=1;i<=n;i++) { for(int j=1;j<=n;j++) { scanf("%d",&map[i][j]); } } maxdl=-1; for(int i=2;i<=n;i++) { scanf("%d",&dl[i]); if(maxdl<dl[i]) maxdl=dl[i]; } floyd(); ans=inf; memset(vis,0,sizeof(vis)); dfs(1,1,0,n-1,0); if(ans==inf) printf("-1\n"); else printf("%d\n",ans); } return 0; }