luoguP1186 瑪麗卡 x
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。用h數組來記錄,當前的點在松弛時,最優的那條邊。記錄邊!!!
之後從終點開始,往回找。由於h裏有當前節點前面的邊。所以可以找到這個圖的最短路徑。之後呢,刪最短路徑就是保證最短路的整體還是有就是堵車的時候不能走最短路,最後也要步走這條邊也要找到最短路。而且找的時候專除小的邊。
1)會T一個點
#include<iostream> #include<cstdio> #include<cstring> using namespace std; struct node { int next,v,t,val; } edge[1000001]; int heads[1000001],d[1010],cnt,head,last,visit[1010],h[1010]; int q[10001];//手寫隊列 int n,m; int add(int x,int y,int z) //領接表,裏面有起點!這個重要。 { edge[++cnt].next=heads[x]; edge[cnt].v=y; edge[cnt].t=x; edge[cnt].val=z; heads[x]=cnt; } int spfa(int x) { memset(d,0x7f,sizeof(d)); d[1]=0; int t=edge[x].val; edge[x].val=0xffff;//刪邊 head=1; last=1; q[last]=1; visit[1]=1; while(head<=last) { int a=q[head]; for(int i=heads[a]; i!=-1; i=edge[i].next) { if(d[edge[i].v]>d[a]+edge[i].val) { if(!visit[edge[i].v]) { q[++last]=edge[i].v; visit[edge[i].v]=0; d[edge[i].v]=d[a]+edge[i].val; } else { d[edge[i].v]=d[a]+edge[i].val; } } } head++; visit[a]=0; } edge[x].val=t; } int main() { memset(d,2147,sizeof(d)); memset(heads,-1,sizeof(heads)); int x,y,z; scanf("%d%d",&n,&m); for(int i=1; i<=m; i++) { scanf("%d%d%d",&x,&y,&z); add(x,y,z); add(y,x,z); } head=1; last=1; q[last]=1; visit[1]=1; d[1]=0; while(head<=last) { int a=q[head]; for(int i=heads[a]; i!=-1; i=edge[i].next) { if(d[edge[i].v]>d[a]+edge[i].val) { if(!visit[edge[i].v]) { q[++last]=edge[i].v; visit[edge[i].v]=0; d[edge[i].v]=d[a]+edge[i].val; h[edge[i].v]=i; //記錄每個點最短路松弛時的邊 } else { d[edge[i].v]=d[a]+edge[i].val; h[edge[i].v]=i;//同上 } } } head++; visit[a]=0; } int b=d[n]; for(int i=n; i!=1; i=edge[h[i]].t) //枚舉從終點一直到起點,刪最短路的一條邊。 { spfa(h[i]); b=max(b,d[n]); } printf("%d",b); return 0; }View Code
2)AC
#include <iostream> #include <cstdio> #include <cstring> #include <queue> using namespace std; const int D = 1001; const int S = 1e6 + 10; const int M = 2e6; struct orz { int next,v,t,val; } edge[S]; int heads[S],d[D],cnt; int v[D],h[D]; int n,m; bool cannot[M]; inline long long read() { int x=0,f=1; char ch=getchar(); while(ch<‘0‘ || ch>‘9‘){ if(ch==‘-‘) f=-1;ch=getchar();} while(ch>=‘0‘ && ch<=‘9‘){ x=x*10+ch-‘0‘; ch=getchar();} return x*f; } int add(int x,int y,int z) ///鄰接表,裏面有起點!這個重要. { edge[++cnt].next=heads[x]; edge[cnt].t=x; edge[cnt].v=y; edge[cnt].val=z; heads[x]=cnt; } int spfa(bool flag) { memset(d,0x7f7f7f,sizeof(d)); memset(v,0,sizeof(v)); queue<int>q; q.push(1); v[1]=1; d[1]=0;///麥克起點為1 while(!q.empty()) { int a=q.front(); q.pop(); v[a]=0; for(int i=heads[a]; i!=-1; i=edge[i].next) { int vv=edge[i].v,val=edge[i].val; if(cannot[a*1001+vv]) continue; if(d[vv]>d[a]+val) { d[vv]=d[a]+val; if(flag) h[vv]=a; if(!v[vv]) { q.push(vv); v[vv]=1; } } } } } int main() { memset(heads,-1,sizeof(heads)); int a,b,c; n=read();m=read(); for(int i=1;i<=m;i++) { a=read(),b=read(),c=read(); add(a,b,c),add(b,a,c); } spfa(1); int ans=d[n]; int y=n; while(y) { cannot[y*1001+h[y]]=1; cannot[h[y]*1001+y]=1; spfa(0); if(d[n]>ans) ans=d[n]; cannot[y*1001+h[y]]=0; cannot[h[y]*1001+y]=0; y=h[y]; } printf("%d\n",ans); return 0; }View Code
luoguP1186 瑪麗卡 x