【2018/10/04測試T3】【WOJ 4038】航班
阿新 • • 發佈:2018-12-13
【題目】
題目描述:
L 因為業務繁忙,經常會到處出差。因為他是航空公司的優質客戶,於是某個航空公司給了他一個優惠券。
他可以利用這個優惠券在任何一個國家內的任意城市間免費旅行,當他的路線跨國才會產生費用。L 有一個航空公司的價格表與航線。而且每個城市出發都能到所有的城市,2 個城市間可能有不止一個航班,一個國家內的 2 個城市間一定有不同的路線,但是不同國家的城市間只有一條路線。L 想知道從每個城市出發到產生費用最多的城市,不過你不能重複在一個航班上飛來飛去產生費用,必須沿最少的費用路線飛行
輸入格式:
第一行,兩個整數 N , M,表示 N 個城市, M 條航線。
接下來 M 行,每行三個整數
輸出格式:
共 N 行,第 i 行為從城市 i 出發到達每個城市額外費用的最大值。
樣例資料:
輸入
6 6 1 4 2 1 2 6 2 5 3 2 3 7 6 3 4 3 1 8
輸出
4 4 4 6 7 7
備註:
【樣例解釋】
有四個國家,包含的城市分別為 { 1 , 2 , 3 } , { 4 } , { 5 } , { 6 }。
從城市 1 出發到達城市 6,乘坐 ( 1 , 3 ) ( 3 , 6 ) 兩個航班費用最大,( 1 , 3 ) 在國內為免費航班, ( 3 , 6 ) 的費用為 4,所以從 1 出發的最大費用為 4。
【資料規模】
對於 40% 的資料 1 ≤ N ≤ 1000,1 ≤ M ≤ 1000
對於 100% 的資料 1 ≤ N ≤ 20000,1 ≤ M ≤ 200000
【分析】
這是一篇比較水的部落格
具體就只有兩種操作:
1、對圖進行縮點,縮點後的圖是一棵樹
2、找樹的直徑,若兩個端點為 A 和 B,則答案
【程式碼】
#include<stack> #include<cstdio> #include<cstring> #include<algorithm> #define N 20005 #define M 500005 using namespace std; int n,m,sum,num,far,len; int t=1,v[M],w[M],next[M],first[N]; int tot=1,vv[M],ww[M],nxt[M],head[N]; int id[N],dfn[N],low[N],dis1[N],dis2[N]; bool insta[N]; stack<int>sta; void add(int x,int y,int z) { t++; next[t]=first[x]; first[x]=t; v[t]=y; w[t]=z; } void edge(int x,int y,int z) { tot++; nxt[tot]=head[x]; head[x]=tot; vv[tot]=y; ww[tot]=z; } void Tarjan(int x,int father) { int i,j; dfn[x]=low[x]=++num; sta.push(x),insta[x]=true; for(i=first[x];i;i=next[i]) { j=v[i]; if(!dfn[j]) { Tarjan(j,x); low[x]=min(low[x],low[j]); } else if(insta[j]&&j!=father) low[x]=min(low[x],dfn[j]); } if(low[x]==dfn[x]) { sum++; do { i=sta.top(); sta.pop(); id[i]=sum; insta[i]=false; } while(i!=x); } } int findfarthest(int x,int father) { int i,j; if(len<dis1[x]) len=dis1[x],far=x; for(i=head[x];i;i=nxt[i]) { j=vv[i]; if(j==father) continue; dis1[j]=dis1[x]+ww[i]; findfarthest(j,x); } } void dfs(int x,int father) { int i,j; for(i=head[x];i;i=nxt[i]) { j=vv[i]; if(j==father) continue; dis2[j]=dis2[x]+ww[i]; dfs(j,x); } } int main() { // freopen("prize.in","r",stdin); // freopen("prize.out","w",stdout); int x,y,z,i,j; scanf("%d%d",&n,&m); for(i=1;i<=m;++i) { scanf("%d%d%d",&x,&y,&z); add(x,y,z),add(y,x,z); } for(i=1;i<=n;++i) if(!dfn[i]) Tarjan(i,0); for(i=1;i<=n;++i) for(j=first[i];j;j=next[j]) if(id[i]!=id[v[j]]) edge(id[i],id[v[j]],w[j]); dis1[1]=0,len=0,findfarthest(1,0); dis1[far]=0,len=0,findfarthest(far,0); dfs(far,0); for(i=1;i<=n;++i) printf("%d\n",max(dis1[id[i]],dis2[id[i]])); // fclose(stdin); // fclose(stdout); return 0; }