[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 }
View Code

总结:这道题其实也可以从最小生成树的思路考虑,一题多解,

这题作为提高组还是比较适宜的,想要练习最短路的同学,可以练练

当然更厉害的,也可以想想更优越的算法

 

posted @ 2017-09-28 17:59  logiccc  阅读(180)  评论(1编辑  收藏  举报