1. 程式人生 > >NOIP 2013 提高組 貨車運輸

NOIP 2013 提高組 貨車運輸

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;
}