noip 2013 货车运输
这个题让我对最小生成树和倍增有了新的理解,这里不得不感谢两个人,吕欣和陈弘毅,聪明的两个人,没有你们的讲解,我始终不明白
难点之一:最大生成树
难点之二:什么时候该添加邻接表和前向星
最大难点:如果使用倍增来记树上路径的最值
代码:
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; #define MAXN 10010 #define MAXM 50010 int ecnt,head[MAXN],deep[MAXN],f[MAXN][30],dis[MAXN],n,m,fat[MAXN],q,jl[MAXN][30]; bool vis[MAXN]; struct node { int fro,next,to,dis; }e[4*MAXN+5],ed[MAXM]; void Add_edge(int from,int to,int dis) { e[++ecnt].next=head[from]; e[ecnt].to=to; e[ecnt].dis=dis; head[from]=ecnt; } void dfs(int u) //更新深度及dis值 { vis[u]=1; for(int i=head[u];i;i=e[i].next) { int v=e[i].to; int d=e[i].dis; if(!vis[v]) { deep[v]=deep[u]+1; dis[v]=dis[u]+d; f[v][0]=u; jl[v][0]=e[i].dis; dfs(v); } } } void init() //i的2^j祖先就是i的2^(j-1)祖先的 2^(j-1)祖先 { for(int j=1;(1<<j)<=n;j++) for(int i=1;i<=n;i++) { if(f[i][j-1]) { f[i][j]=f[f[i][j-1]][j-1]; jl[i][j]=min(jl[i][j-1],jl[f[i][j-1]][j-1]);//在倍增的过程中找距离 } } } int LCA(int a,int b) { if(deep[a]<deep[b]) swap(a,b); //使a成为深度较深的那个点 int i; for(i=0;(1<<i)<=deep[a];i++); i--; for(int j=i;j>=0;j--) //使a,b深度相同 { if(deep[a]-(1<<j)>=deep[b]) a=f[a][j]; } if(a==b) return a; //同一层同一节点 for(int j=i;j>=0;j--)//一直向上找,找到两个节点不同的最靠上的那一个 { if(f[a][j]&&f[a][j]!=f[b][j]) { a=f[a][j]; b=f[b][j]; } } return f[a][0];//返回他们的父亲 } int father(int x) { if(fat[x]!=x) fat[x]=father(fat[x]); return fat[x]; } int unio(int x,int y) { int fx=father(x); int fy=father(y); if(fx!=fy) fat[fy]=fx; } int cmp(const node &a,const node &b) { if(a.dis>b.dis) return 1; else return 0; } int query(int s,int s1) { int mn=0x7f7f7f7f; int t=deep[s]-deep[s1];//t的主要作用是保证他们不在同一层 for(int i=0;(1<<i)<=n;i++) { if(t&(1<<i)) { mn=min(mn,jl[s][i]);//一直往上移动 s=f[s][i]; } } return mn; } int main() { freopen("truck.in","r",stdin); freopen("truck.out","w",stdout); scanf("%d%d",&n,&m); int a,b,c,k=0; for(int i=1;i<=n;i++) fat[i]=i; for(int i=1;i<=m;i++) { scanf("%d%d%d",&a,&b,&c); ed[i].fro=a,ed[i].to=b,ed[i].dis=c; } sort(ed+1,ed+1+m,cmp); for(int i=1;i<=m;i++) { if(father(ed[i].fro)!=father(ed[i].to)) { Add_edge(ed[i].fro,ed[i].to,ed[i].dis); Add_edge(ed[i].to,ed[i].fro,ed[i].dis); unio(ed[i].fro,ed[i].to); k++; } if(k==n-1) break; } for(int i=1;i<=n;i++) if(!vis[i]) dfs(i); init(); scanf("%d",&q); for(int i=1;i<=q;i++) { scanf("%d%d",&a,&b); if(father(a)==father(b)) { int s=LCA(a,b); cout<<min(query(a,s),query(b,s))<<endl; } else cout<<"-1"<<endl; } } /** LCA(a,b) 4 3 1 2 4 2 3 3 3 1 1 3 1 3 1 4 1 3 5 7 4 3 4440 3 1 22348 1 3 28368 2 4 25086 5 3 6991 4 3 10638 3 1 11106 4 4 5 1 3 5 4 2 5 6991 28368 6991 6991 **/

浙公网安备 33010602011771号