[XJOI]noip45 T2 图
***图***
解题思路:这题的原题似乎好像是NOI某年的题目,然后数据改水了
于是就可以用一些简单的最短路算法水掉.
因为他是要求max(a)+max(b)的值,所以单纯的最短路是不行的
我们可以枚举最大的a值,即能走的边a值要小于这个限制,然后对b跑一遍最短路,每次更新答案
当然这是我的辣鸡做法,只能满足这道题的数据,更优越的算法是用lct来维护
读者可以去各大OJ做 魔法森林这道题
https://www.luogu.org/problem/show?pid=2387 在此只贴了luogu的网址
1 %:pragma GCC optimize(2) 2 #include<bits/stdc++.h> 3 using namespace std; 4 const int N=200010; 5 int to[N],fst[N],nxt[N],fa[N],t[N]; 6 long long dis[N],a[N],b[N],ans=1e13; 7 int x,y,aa,bb,tot=0,n,m; 8 bool vis[N]; 9 inline void add(int x,int y,int aa,int bb){ 10 to[++tot]=y; nxt[tot]=fst[x]; fst[x]=tot; a[tot]=aa; b[tot]=bb; 11 } 12 inline int ask(int x){ 13 if (fa[x]==x) return x; fa[x]=ask(fa[x]); return fa[x]; 14 } 15 struct cmp{bool operator ()(int a,int b){return dis[a]>dis[b];}}; 16 priority_queue <int,vector<int>,cmp> q; 17 inline void dij(int lim){ 18 for (int i=1;i<=n;++i) dis[i]=1e13; 19 memset(vis,0,sizeof(vis)); 20 dis[1]=0; q.push(1); 21 while (!q.empty()){ 22 int t=q.top(); q.pop(); 23 if (vis[t]) continue; vis[t]=1; 24 for (int i=fst[t];i;i=nxt[i]) 25 if (a[i]<=lim&&dis[to[i]]>max(dis[t],b[i])) 26 dis[to[i]]=max(dis[t],b[i]),q.push(to[i]); 27 } 28 } 29 30 int main(){ 31 scanf("%d%d",&n,&m); 32 for (int i=1;i<=n;++i) fa[i]=i; 33 for (int i=1;i<=m;++i){ 34 scanf("%d %d %d %d",&x,&y,&aa,&bb); 35 add(x,y,aa,bb); add(y,x,aa,bb); fa[ask(x)]=ask(y); 36 } 37 if (ask(fa[1])!=ask(fa[n])){ 38 printf("-1"); return 0; 39 } 40 for (int i=1;i<=tot;++i){ 41 dij(a[i]); ans=min(ans,a[i]+dis[n]); 42 } 43 if (ans>=1e13) printf("-1"); 44 else printf("%lld\n",ans); 45 }
总结:这道题其实也可以从最小生成树的思路考虑,一题多解,
这题作为提高组还是比较适宜的,想要练习最短路的同学,可以练练
当然更厉害的,也可以想想更优越的算法