Codevs 1021 玛丽卡==洛谷 P1186
时间限制: 2 s 空间限制: 128000 KB 题目等级 : 大师 Master
题目描述 Description
麦克找了个新女朋友,玛丽卡对他非常恼火并伺机报复。
因为她和他们不住在同一个城市,因此她开始准备她的长途旅行。
在这个国家中每两个城市之间最多只有一条路相通,并且我们知道从一个城市到另一个城市路上所需花费的时间。
麦克在车中无意中听到有一条路正在维修,并且那儿正堵车,但没听清楚到底是哪一条路。无论哪一条路正在维修,从玛丽卡所在的城市都能到达麦克所在的城市。
玛丽卡将只从不堵车的路上通过,并且她将按最短路线行车。麦克希望知道在最糟糕的情况下玛丽卡到达他所在的城市需要多长时间,这样他就能保证他的女朋友离开该城市足够远。
编写程序,帮助麦克找出玛丽卡按最短路线通过不堵车道路到达他所在城市所需的最长时间(用分钟表示)。
输入描述 Input Description
第一行有两个用空格隔开的数N和M,分别表示城市的数量以及城市间道路的数量。1≤N≤1000,1≤M≤N*(N-1)/2。城市用数字1至N标识,麦克在城市1中,玛丽卡在城市N中。
接下来的M行中每行包含三个用空格隔开的数A,B和V。其中1≤A,B≤N,1≤V≤1000。这些数字表示在A和城市B中间有一条双行道,并且在V分钟内是就能通过。
输出描述 Output Description
输出文件的第一行中写出用分钟表示的最长时间,在这段时间中,无论哪条路在堵车,玛丽卡应该能够到达麦克处,如果少于这个时间的话,则必定存在一条路,该条路一旦堵车,玛丽卡就不能够赶到麦克处。
样例输入 Sample Input
5 7
1 2 8
1 4 10
2 3 9
2 4 10
2 5 1
3 4 7
3 5 10
样例输出 Sample Output
27
1 #include<iostream>
2 #include<cstdio>
3 #include<cstring>
4 #include<queue>
5 using namespace std;
6 int map[1000][1000],pre[1010],dis[1010],lu[1010];
7 int n,m,tot,ans=0;
8 bool exist[1010];
9 void SPFA(int s)
10 {
11 queue<int> q;
12 memset(dis,0x3f,sizeof(dis));
13 memset(exist,false,sizeof(exist));
14 dis[1]=0;exist[s]=true;q.push(s);
15 while(!q.empty()){
16 int x=q.front();q.pop();
17 exist[x]=false;
18 for(int i=1;i<=n;i++)
19 {
20 if(dis[i]>dis[x]+map[x][i]){
21 dis[i]=dis[x]+map[x][i];pre[i]=x;
22 if(exist[i]==false){
23 q.push(i);exist[i]=true;
24 }
25 }
26 }
27 }
28 }
29 void dij()
30 {
31 int minl,k;
32 memset(dis,0x3f,sizeof(dis));
33 memset(exist,false,sizeof(exist));
34 dis[1]=0;
35 for(int i=1;i<=n;i++)
36 {
37 minl=0x5f;
38 for(int j=1;j<=n;j++)
39 if(exist[j]==false&&dis[j]<minl)
40 k=j,minl=dis[j];
41 exist[k]=true;
42 for(int j=1;j<=n;j++)
43 if(map[k][j]!=0&&dis[j]>dis[k]+map[k][j])
44 dis[j]=dis[k]+map[k][j];
45 }
46 }
47 int main()
48 {
49 scanf("%d%d",&n,&m);
50 for(int i=1,x,y,z;i<=m;i++){
51 scanf("%d%d%d",&x,&y,&z);
52 map[x][y]=map[y][x]=z;
53 }
54 pre[1]=0;
55 SPFA(1);
56 ans=max(ans,dis[n]);
57 ++tot;lu[tot]=n;
58 int p=n;
59 while(pre[p]!=0){
60 ++tot;
61 lu[tot]=pre[p];
62 p=pre[p];
63 }
64 for(int i=1;i<=tot-1;i++){
65 int k=map[lu[i]][lu[i+1]];
66 map[lu[i]][lu[i+1]]=0;
67 map[lu[i+1]][lu[i]]=0;
68 dij();
69 ans=max(ans,dis[n]);
70 map[lu[i]][lu[i+1]]=k;
71 map[lu[i+1]][lu[i]]=k;
72 }
73 printf("%d",ans);
74 return 0;
75 }
以上是我的代码 本人认为没毛病,求大神解救~~
AC代码:
1 #include<iostream>
2 #include<cstdio>
3 #include<algorithm>
4 #include<cstring>
5 #include<queue>
6 using namespace std;
7 const int maxn = 1005;
8 const int maxm = maxn*(maxn - 1)/2;
9 struct Edge
10 {
11 int u,v,w,next;
12 } edge[maxm];
13 int head[maxm],vis[maxn],dis[maxn],prev[maxn];
14 int N,M,tot = 0,res;
15
16 void addedge(int u,int v,int w)
17 {
18 edge[tot] = (Edge)
19 {
20 u,v,w,head[u]
21 };
22 head[u] = tot++;
23 }
24
25 int spfa(int x,int y) //虽然玛丽卡在第N个城市,但是1-N的最短距离固定,
26 { // 所以我们可以从第1个城市出发,求出1-N的最短路
27 memset(dis,0x3f,sizeof(dis));
28 memset(vis,0,sizeof(vis));
29 queue<int>que;
30 dis[1] = 0;
31 que.push(1);
32 vis[1] = 1;
33 while (!que.empty())
34 {
35 int u = que.front();
36 que.pop();
37 vis[u] = 0;
38 for (int i = head[u]; i != -1; i = edge[i].next)
39 {
40 int v = edge[i].v;
41 if ((u == x && v == y) || (u == y && v == x)) continue;
42 if (dis[u] + edge[i].w < dis[v])
43 {
44 dis[v] = dis[u] + edge[i].w;
45 prev[v] = u; //记录前驱(路径)
46 if (!vis[v])
47 {
48 que.push(v);
49 vis[v] = 1;
50 }
51 }
52 }
53 }
54 return dis[N];
55 }
56
57 int main()
58 {
59
60 int u,v,w;
61 memset(head,-1,sizeof(head));
62 memset(prev,0,sizeof(prev));
63 scanf("%d%d",&N,&M);
64 for (int i = 0; i < M; i++)
65 {
66 scanf("%d%d%d",&u,&v,&w);
67 addedge(u,v,w);
68 addedge(v,u,w);
69 }
70 res = spfa(0,0);
71 int tmp = N;
72 queue<int>q;
73 while (tmp)
74 {
75 q.push(tmp);
76 tmp = prev[tmp];
77 }
78 while (q.size() > 1)
79 {
80 tmp = q.front();
81 q.pop();
82 res = max(res,spfa(tmp,q.front()));
83 }
84 printf("%d\n",res);
85 return 0;
86 }
我们可以用一遍SPFA,求出最短路,然后不难发现,炸最短路上的边可以是答案变得更大,而炸掉非最短路上的边对答案没任何影响