1. 程式人生 > >P1186 瑪麗卡

P1186 瑪麗卡

math struct clas 不能 並且 ont head amp push_back

P1186 瑪麗卡

題目描述

麥克找了個新女朋友,瑪麗卡對他非常惱火並伺機報復。

因為她和他們不住在同一個城市,因此她開始準備她的長途旅行。

在這個國家中每兩個城市之間最多只有一條路相通,並且我們知道從一個城市到另一個城市路上所需花費的時間。

麥克在車中無意中聽到有一條路正在維修,並且那兒正堵車,但沒聽清楚到底是哪一條路。無論哪一條路正在維修,從瑪麗卡所在的城市都能到達麥克所在的城市。

瑪麗卡將只從不堵車的路上通過,並且她將按最短路線行車。麥克希望知道在最糟糕的情況下瑪麗卡到達他所在的城市需要多長時間,這樣他就能保證他的女朋友離開該城市足夠遠。

編寫程序,幫助麥克找出瑪麗卡按最短路線通過不堵車道路到達他所在城市所需的最長時間(用分鐘表示)。

輸入輸出格式

輸入格式:

第一行有兩個用空格隔開的數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分鐘內是就能通過。

輸出格式:

輸出文件的第一行中寫出用分鐘表示的最長時間,在這段時間中,無論哪條路在堵車,瑪麗卡應該能夠到達麥克處,如果少於這個時間的話,則必定存在一條路,該條路一旦堵車,瑪麗卡就不能夠趕到麥克處。

輸入輸出樣例

輸入樣例#1:
5 7
1 2 8
1 4 10
2 3 9
2 4 10
2 5 1
3 4 7
3 5 10
輸出樣例#1:
27

分析:

方法一: spfa+spfa

先SPFA求出最短路,然後枚舉去掉哪條邊,再跑n次spfa,記錄結果得出最大的方案。

這道題可以用圖論求最短路解決,第一次跑最短路時記錄最短路上的每條邊(這裏的邊是無向的),然後再依次刪除最短路上的每一條邊(因為刪除其他邊最短路不變,所以只需刪最短路上的便就行了),再跑SPFA。

註意!!!SPFA再這道題上會有一個點超時,這裏介紹一種簡單而又實用的優化方法

SLF優化:將某個點加入隊列是,設當前點為 v,隊首元素為u,若dist[v] < dist[u],即把 v 加入到隊列的頭部,否則加入到隊列尾部。

用雙端隊列deque實現。

優化思想就是:利用價值最大的點最先處理

  1 #include<cstdio>
  2 #include<iostream>
  3 #include<algorithm>
  4 #include<deque>
  5 #include<cstring>
  6 
  7 using namespace std;
  8 
  9 struct edge
 10 {
 11     int v;
 12     int next;
 13     int w;
 14 }e[1000050];
 15 
 16 int ans,dist[1005],p[1005],head[1005],cnt,delu,delv;
 17 bool vis[1005];
 18 
 19 void add(int u,int v,int w)//添加邊
 20 {
 21     e[++cnt] = (edge){v,head[u],w};
 22     head[u] = cnt;
 23 }
 24 
 25 int read() //讀入優化 
 26 {
 27     int ans=0;char ch = getchar();
 28     while(ch<0||ch>9)    ch = getchar();
 29     while(ch>=0&&ch<=9) {ans = ans *10 + ch - 0;ch = getchar();}
 30     return ans;
 31 }
 32 
 33 void spfa()
 34 {
 35     int v,u;
 36     deque<int> q;//雙向隊列
 37     memset(dist,-1,sizeof(dist));
 38     memset(vis,false,sizeof(vis));
 39     q.push_back(1);
 40     dist[1] = 0;
 41     vis[1] = true;
 42     while(!q.empty())
 43     {
 44         u = q.front();
 45         q.pop_front();
 46         for(int i=head[u];i;i=e[i].next)
 47         {
 48             v = e[i].v;
 49             if(dist[v]<0 || dist[v]>dist[u]+e[i].w)
 50             {
 51                 if(!(u==delu&&v==delv)||(v==delu&&u==delv))//判斷邊是否被刪除
 52                 {
 53                     dist[v] = dist[u] + e[i].w;
 54                     if(!ans)//如果已經跑過一次最短路就不要記錄邊了
 55                         p[v] = u;
 56                     if(!vis[v])
 57                     {
 58                         if(!q.empty())
 59                         {
 60                             if(dist[v]<dist[q.front()])
 61                                 q.push_front(v);
 62                             else
 63                                 q.push_back(v);
 64                         }
 65                         else
 66                             q.push_back(v);
 67                         vis[v] = true;
 68                     }
 69                 }
 70             }
 71         }
 72         vis[u] = false;
 73     }
 74 }
 75 
 76 int main()
 77 {
 78     int n,m;
 79     n=read();
 80     m=read(); 
 81     for(int i=1;i<=m;i++)
 82     {
 83         int u,v,w;
 84         u=read();
 85         v=read();
 86         w=read();
 87         add(u,v,w);
 88         add(v,u,w);
 89     }
 90     spfa();
 91     ans = dist[n];
 92     for(int i = n;i!=1;i = p[i])
 93     {
 94         delu = p[i];//依次刪除最短路上的邊
 95         delv = i;
 96         spfa();
 97         ans = max(dist[n],ans);
 98     }
 99     printf("%d",ans);
100     return 0;
101 }

方法二:

堆優化的dijkstra(用優先隊列實現)

先dijkstra求出最短路,然後枚舉去掉哪條邊,再跑n次dijkstra,記錄結果得出最大的方案。

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <cmath>
 4 #include <cstdlib>
 5 #include <algorithm>
 6 #include <string>
 7 #include <vector>
 8 #include <queue>
 9 #include <iostream>
10 using namespace std;
11 const int maxn=1000+20,inf=1234567890;
12 typedef pair<int,int> P;
13 struct edge{int to,w;};
14 vector<edge>G[maxn];
15 int n,m,pre[maxn],d[maxn];
16 priority_queue<P,vector<P>,greater<P> >que;
17 void read(int &n){
18     n=0;int f=1;
19     char ch=getchar();
20     while(ch<0 || ch>9){
21         if(ch==-) f=-1;
22         ch=getchar();
23     }
24     do{
25         n=n*10+ch-0;
26         ch=getchar();
27     }while(ch>=0 && ch<=9);
28     n=n*f;
29     return;
30 }
31 void write(int n){
32     if(n<0){
33         putchar(-);
34         n=0-n;
35     }
36     if(n>=10) write(n/10);
37     putchar((n % 10)+0);
38     return;
39 }
40 inline void add_edge(int u,int v,int w){
41     edge e;e.to=v;e.w=w;
42     G[u].push_back(e);
43     return;
44 }
45 void init(){
46     read(n);read(m);
47     for(int i=1;i<=m;i++){
48         int u,v,w;
49         read(u);read(v);read(w);
50         add_edge(u,v,w);
51         add_edge(v,u,w);
52     }
53     return;
54 }
55 int dijkstra(int f,int ff){
56     for(int i=1;i<=n;i++) d[i]=inf;
57     d[1]=0;
58     P p(0,1);que.push(p);
59     while(!que.empty()){
60         P temp=que.top();
61         que.pop();
62         int u=temp.second;
63         if(d[u]<temp.first) continue;
64         for(int i=0;i<G[u].size();i++){
65             int v=G[u][i].to;
66             if(f==u && ff==v) continue;
67             if(ff==u && f==v) continue;
68             int w=G[u][i].w;
69             int t=d[u]+w;
70             if(d[v]>t){
71                 d[v]=t;
72                 que.push(P(t,v));
73                 if(!f && !ff) pre[v]=u;
74             }
75         }
76     }
77     return d[n];
78 }
79 void solve(){
80     memset(pre,-1,sizeof(pre));
81     int ans=dijkstra(0,0);
82     int u=n;
83     while(pre[u]!=-1){
84         int r=dijkstra(u,pre[u]);
85         if(r!=inf) ans=max(ans,r);
86         u=pre[u];
87     }
88     write(ans);
89     return;
90 }
91 int main(){
92     init();
93     solve();
94     return 0;
95 }



P1186 瑪麗卡