洛谷1186 玛丽卡
本题地址: http://www.luogu.org/problem/show?pid=1186
题目描述
麦克找了个新女朋友,玛丽卡对他非常恼火并伺机报复。
因为她和他们不住在同一个城市,因此她开始准备她的长途旅行。
在这个国家中每两个城市之间最多只有一条路相通,并且我们知道从一个城市到另一个城市路上所需花费的时间。
麦克在车中无意中听到有一条路正在维修,并且那儿正堵车,但没听清楚到底是哪一条路。无论哪一条路正在维修,从玛丽卡所在的城市都能到达麦克所在的城市。
玛丽卡将只从不堵车的路上通过,并且她将按最短路线行车。麦克希望知道在最糟糕的情况下玛丽卡到达他所在的城市需要多长时间,这样他就能保证他的女朋友离开该城市足够远。
编写程序,帮助麦克找出玛丽卡按最短路线通过不堵车道路到达他所在城市所需的最长时间(用分钟表示)。
输入输出格式
输入格式:
第一行有两个用空格隔开的数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
【思路】
最短路+断边。
简单的思路就是直接枚举m条边尝试切断并求最短路,比较得最大的d[n],但时间很差。
通过SPFA我们可以构建一棵最短路树,不难发现,只要不删除最短路上的边就不会影响最短路径,因此可以采用枚举最短路树上的边尝试切断。但依然有2个点过不了。
进一步思考发现,我们求的是1到n的最短路,所以只需要枚举1n最短路径上的边尝试切断就可以了。
注意边从0开始编号才能使用 ^ 的方法得反向边。
注:与求解次短路的方法同
【代码】
1 #include<cstdio> 2 #include<queue> 3 #include<cstring> 4 #include<vector> 5 using namespace std; 6 7 const int maxn = 1000+10; 8 const int INF=1<<30; 9 struct Edge{ 10 int v,w,next; 11 }e[maxn*maxn]; //2 12 int en=-1,front[maxn]; //en=-1 边自0开始编号 13 14 int n,m; 15 vector<int> es; 16 17 inline void AddEdge(int u,int v,int w) { 18 en++; e[en].v=v; e[en].w=w; e[en].next=front[u]; front[u]=en; 19 } 20 21 int SPFA(int* P) { 22 int inq[maxn],d[maxn]; 23 queue<int> q; 24 memset(inq,0,sizeof(inq)); 25 for(int i=1;i<=n;i++) d[i]=INF; 26 27 d[1]=0; inq[1]=1; q.push(1); 28 while(!q.empty()) { 29 int u=q.front(); q.pop(); inq[u]=0; 30 for(int i=front[u];i>=0;i=e[i].next) { 31 int v=e[i].v,w=e[i].w; 32 if(d[v]>d[u]+w) { 33 P[v]=u; 34 d[v]=d[u]+w; 35 if(!inq[v]) { 36 inq[v]=1; 37 q.push(v); 38 } 39 } 40 } 41 } 42 return d[n]; 43 } 44 45 void dfs(int u,int*p) { 46 if(p[u]) dfs(p[u],p); 47 int x=0; 48 for(int i=front[u];i>=0;i=e[i].next) 49 if(e[i].v==p[u]) { 50 es.push_back(i); break; 51 } 52 } 53 54 int main() { 55 memset(front,-1,sizeof(front)); 56 scanf("%d%d",&n,&m); 57 int u,v,w; 58 for(int i=0;i<m;i++) { 59 scanf("%d%d%d",&u,&v,&w); 60 AddEdge(u,v,w); 61 AddEdge(v,u,w); 62 } 63 int p[maxn]; 64 SPFA(p); 65 dfs(n,p); 66 int tmp1,tmp2,t[maxn],ans=0; 67 for(int i=0;i<es.size();i++) { 68 int x=es[i]; 69 tmp1=e[x].w, tmp2=e[x^1].w; //双向边 01 23 45 70 e[x].w=e[x^1].w=INF; 71 ans=max(ans, SPFA(t)); //断一条边最小路 72 e[x].w=tmp1; e[x^1].w=tmp2; 73 } 74 printf("%d ",ans); 75 return 0; 76 }
可以省去dfs,p记录入边同时Edge增加u指向前一个相邻点。
查找改为:
1 double tmp1,tmp2,ans=INF; 2 int t[maxn]; 3 for(int x=p[n];x>=0;x=p[e[x].u]) { 4 tmp1=e[x].w, tmp2=e[x^1].w; //双向边 01 23 45 5 e[x].w=e[x^1].w=INF; 6 ans=min(ans, SPFA(t)); //断一条边最小路 7 e[x].w=tmp1; e[x^1].w=tmp2; 8 }