NOIP 2013 提高組 貨車運輸
阿新 • • 發佈:2019-01-27
NOIP 2013 提高組 Day 1
簡單說一下本題思路吧。
題目要求每輛車在不超過車輛限重的情況下,最多能運多重的貨物
顯然有一點點優化,如果兩個道路間有多條道路,顯然你要讓貨車走限重最大的道路。
那麼大家應該都知道有一個叫最小生成樹的克魯斯卡爾演算法吧。 這道題其實一開始要先求一個圖的最大生成樹,
這樣只要車走這些道路,就可以滿足限重最大。當然,這棵最大生成樹不一定能求出來,因為有的點之間不能相互連通。
那麼怎麼快速判斷兩點是否連通呢? 嗯 沒錯,你可以使用並查集維護,對的對的,最好是帶路徑壓縮的並查集維護,
這樣能更快一些。 至於求兩點間限重最小值的話,你可以把一號節點作為根節點,建立一棵樹,然後對每個點標上等級標記,求這兩個點
之間的限重的最小值的話,比較暴力的可以直接模擬往上找兩個點的最近公共祖先,可以AC的,聰明的可以去寫倍增的LCA,也很強勢;
如果不太懂得話可以好好看一下我程式碼裡的work過程,好好看應該很快就能懂,原諒小武不能在這裡用語言描述清楚,怪我嘍QAQ;
#include<set> #include<map> #include<cmath> #include<queue> #include<stack> #include<cstdio> #include<vector> #include<cstring> #include<cstdlib> #include<iostream> #include<algorithm> #define MAXN 10005 #define MAXM 100005 using namespace std; struct Edge { int from; int to; int val; int next; }; int n; int m; int q; int cnt; int num; int f[MAXN]; int lv[MAXN]; int vis[MAXN]; int dis[MAXN]; int pre[MAXN]; int head[MAXN]; Edge s[MAXM],edge[MAXM]; inline bool cmp(Edge x,Edge y) { return x.val>y.val; } inline int find(int x) { if (f[x]!=x) return f[x]=find(f[x]); return f[x]; } inline void add(int u,int v,int w) { edge[++cnt].from=u; edge[cnt].to=v; edge[cnt].val=w; edge[cnt].next=head[u]; head[u]=cnt; return ; } inline void dfs(int u) { for (int i=head[u];i;i=edge[i].next) { int v=edge[i].to; if (!vis[v]) { pre[v]=u; vis[v]=1; dis[v]=min(dis[v],edge[i].val); lv[v]=lv[u]+1; dfs(v); } } return ; } inline int work(int x,int y) { int ans=100005; while(lv[x]>lv[y]) ans=min(ans,dis[x]),x=pre[x]; while(lv[y]>lv[x]) ans=min(ans,dis[y]),y=pre[y]; while(x!=y) ans=min(ans,min(dis[x],dis[y])),x=pre[x],y=pre[y]; return ans; } inline void solve() { scanf("%d%d",&n,&m); memset(dis,0x7f,sizeof(dis)); for (int i=1;i<=n;i++) f[i]=i; for (int i=1;i<=m;i++) scanf("%d%d%d",&s[i].from,&s[i].to,&s[i].val); sort(s+1,s+1+m,cmp); num=0; cnt=0; for (int i=1;i<=m&&num!=n-1;i++) { int fa=find(s[i].from); int fb=find(s[i].to); if (fa!=fb) { f[fa]=fb; num++; add(s[i].from,s[i].to,s[i].val); add(s[i].to,s[i].from,s[i].val); } } scanf("%d",&q); memset(vis,0,sizeof(vis)); for (int i=1;i<=n;i++) if (!vis[i]) pre[i]=0,lv[i]=vis[i]=1,dfs(i); for (int i=1;i<=q;i++) { int a; int b; scanf("%d%d",&a,&b); int fa=find(a); int fb=find(b); if (fa!=fb) printf("-1\n"); else printf("%d\n",work(a,b)); } return ; } int main() { solve(); return 0; }