题目网址:http://acm.hdu.edu.cn/showproblem.php?pid=3873
思路:
军队可以先等待在城市外面,等保护该城市的城市都被攻破后,直接进城(即进城不用耗费时间)。则进入该城市的最少时间为max(达到该城市的最少时间,到达保护该城市的所有城市的最大时间)。
用num[i]标记第i个城市被保护的数目,只有当该点被保护的数目为0时,才能入S集合,从而优化到其他点的时间。当前进入S集合的城市,遍历它所保护的城市,num[i]减一,记录下被保护的城市解除保护所需的最长时间。
说的有点绕,看代码会比较清楚。
需要注意的一点!!有重边,所以读边的时候要注意,如果是用邻接表就无所谓啦,但如果是用邻接矩阵 要读入最小值。
代码:
1 #include <cstdio> 2 #include <vector> 3 #include <cstring> 4 #include <algorithm> 5 using namespace std; 6 const int inf=1e8+5; 7 int n,m; 8 int num[3005]; 9 int dist[3005]; 10 int S[3005]; 11 int edge[3005][3005]; 12 int rp[3005];//rp[i]表示攻破保护i城市的所有城市所需要的最长时间 13 vector<int>city[3005]; 14 void init(){ 15 memset(num, 0, sizeof(num)); 16 memset(rp, 0, sizeof(rp)); 17 memset(S, 0, sizeof(S)); 18 for (int i=1; i<=n; i++) { 19 city[i].clear(); 20 dist[i]=inf; 21 } 22 for (int i=1; i<=n; i++) { 23 for (int j=1; j<=n; j++) { 24 edge[i][j]=inf; 25 } 26 } 27 } 28 void dijkstra(){ 29 dist[1]=0; 30 for(int i=0;i<n;i++){ 31 int Min=inf,u=-1; 32 for (int j=1; j<=n; j++) { 33 dist[j]=max(dist[j], rp[j]);//每次遍历前 都要更新时间 34 if(dist[j]<Min && !num[j] && !S[j]){ 35 Min=dist[j]; 36 u=j; 37 } 38 } 39 if(u==-1) return ; 40 S[u]=1; 41 for (int j=0; j<city[u].size(); j++) {//更新保护的城市信息 42 int t=city[u][j]; 43 num[t]--; 44 rp[t]=max(rp[t],dist[u]); 45 } 46 city[u].clear(); 47 for (int j=1; j<=n; j++) { 48 if(dist[j]>dist[u]+edge[u][j] && !S[j]){ 49 dist[j]=dist[u]+edge[u][j]; 50 } 51 } 52 } 53 } 54 int main(){ 55 int t; 56 scanf("%d",&t); 57 while (t--) { 58 scanf("%d%d",&n,&m); 59 init(); 60 for(int i=0;i<m;i++){ 61 int v,u,w; 62 scanf("%d%d%d",&v,&u,&w); 63 edge[v][u]=min(edge[v][u],w);//保留最小值 64 65 } 66 for(int i=1;i<=n;i++){ 67 int a,b; 68 scanf("%d",&a); 69 num[i]=a;//记录保护i城市的所有城市数量 70 for (int j=0; j<a; j++) { 71 scanf("%d",&b); 72 city[b].push_back(i);//city[b]为b城市 要保护的城市 73 } 74 } 75 dijkstra(); 76 printf("%d\n",dist[n]); 77 } 78 return 0; 79 }
时间: 2024-11-24 16:57:51