NOIP2013货车运输
2016-10-06 18:02
246 查看
题目来源https://www.luogu.org/problem/show?pid=1967
60分
Kruskal+SPFA
先用Kruskal构造出最大生成树,再在树上跑SPFA,过掉60%的数据。
100分
Kruskal+LCA
倍增思想。
anc[i][k]表示从节点i向上走2^k步所到达的节点。
更新:anc[x][i]=anc[anc[x][i-1]][i-1]
lcs[i][k]表示从节点i向上走2^k步的过程中经过的权值最小的边。
更新:lcs[x][i]=min(lcs[x][i-1],lcs[anc[x][i-1]][i-1]);
在dfs构造anc[i][k]的同时构造lcs[i][k]。
在线查询节点x,y的lca的同时找出其经过的路径之中边权的最小值。
dep数组表示节点的深度,swim函数是将两节点调到同一深度,并记录经过路径的最小权值。
100分代码
60分
Kruskal+SPFA
先用Kruskal构造出最大生成树,再在树上跑SPFA,过掉60%的数据。
#include <algorithm> #include <iostream> #include <cstring> #include <sstream> #include <cstdlib> #include <string> #include <cstdio> #include <cctype> #include <vector> #include <ctime> #include <cmath> #include <stack> #include <queue> #include <set> #include <map> using namespace std; const int maxn=50001; int r[maxn],p[maxn],u[maxn],v[maxn],w[maxn]; bool cmp(const int i,const int j){return w[i]>w[j];} int find(int x) { if(p[x]==x)return x; return p[x]=find(p[x]); } const int maxm=1001; struct edge{int l,t;}; vector<edge> a[maxn]; bool inq[maxm]={0}; int dis[maxm][maxm]={0}; const int inf=1000000000; int main() { ios::sync_with_stdio(false); int n,m;cin>>n>>m; for(int i=1;i<=m;i++) { int x,y,z;cin>>x>>y>>z; u[i]=x;v[i]=y;w[i]=z; } for(int i=1;i<=n;i++)p[i]=i; for(int i=1;i<=m;i++)r[i]=i; sort(r+1,r+1+m,cmp); for(int i=1;i<=m;i++) { int e=r[i]; int x=find(v[e]); int y=find(u[e]); if(x!=y) { p[x]=y; edge r; r.t=y;r.l=w[e]; a[x].push_back(r); r.t=x; a[y].push_back(r); } } int q;cin>>q; for(int i=1;i<=n;i++) { for(int j=1;j<=n;j++) { dis[i][j]=inf; } } for(int k=1;k<=q;k++) { int x,y; cin>>x>>y; if(dis[x][y]<inf) { cout<<dis[x][y]<<endl; continue; } if(dis[y][x]<inf) { cout<<dis[y][x]<<endl; continue; } int dist[maxm]; for(int i=1;i<=n;i++)dist[i]=inf; queue<int> Q; memset(inq,0,sizeof(inq)); Q.push(x);inq[x]=1; while(!Q.empty()) { int e=Q.front();Q.pop(); for(int i=0;i<a[e].size();i++) { if(a[e][i].t==x)continue; if(dist[a[e][i].t]==inf) { dist[a[e][i].t]=min(dist[e],a[e][i].l); if(!inq[a[e][i].t]) { inq[a[e][i].t]=1; Q.push(a[e][i].t); } } else if(dist[a[e][i].t]<min(dist[e],a[e][i].l)) { dist[a[e][i].t]=min(dist[e],a[e][i].l); if(!inq[a[e][i].t]) { inq[a[e][i].t]=1; Q.push(a[e][i].t); } } } inq[e]=0; } for(int i=1;i<=n;i++) { if(dist[i]==inf)dis[x][i]=-1; else dis[x][i]=dist[i]; } cout<<dis[x][y]<<endl; } return 0; }
100分
Kruskal+LCA
倍增思想。
anc[i][k]表示从节点i向上走2^k步所到达的节点。
更新:anc[x][i]=anc[anc[x][i-1]][i-1]
lcs[i][k]表示从节点i向上走2^k步的过程中经过的权值最小的边。
更新:lcs[x][i]=min(lcs[x][i-1],lcs[anc[x][i-1]][i-1]);
在dfs构造anc[i][k]的同时构造lcs[i][k]。
在线查询节点x,y的lca的同时找出其经过的路径之中边权的最小值。
dep数组表示节点的深度,swim函数是将两节点调到同一深度,并记录经过路径的最小权值。
100分代码
#include <algorithm> #include <iostream> #include <cstring> #include <sstream> #include <cstdlib> #include <string> #include <cstdio> #include <cctype> #include <vector> #include <ctime> #include <cmath> #include <stack> #include <queue> #include <set> #include <map> using namespace std; const int maxn=10001; const int maxm=50001; const int maxh=21; const int inf=1000000000; int r[maxm],p[maxm],u[maxm],v[maxm],w[maxm]; struct edge{int l,t;}; vector<edge> a[maxn]; int n,m; int dep[maxn]={0}; int s[maxn]={0}; //stack<int> s; int anc[maxn][maxh]={0}; int lcs[maxn][maxh]={0}; int wr[maxn]={0}; bool cmp(const int i,const int j){return w[i]>w[j];} int find(int x afe3 ) { if(p[x]==x)return x; return p[x]=find(p[x]); } void dfs(int root) { int top=0; dep[root]=1; for(int i=0;i<maxh;i++) { anc[root][i]=root; lcs[root][i]=inf; } s[++top]=root; while(top) { int x=s[top--]; if(x!=root)for(int i=1;i<maxh;i++) { anc[x][i]=anc[anc[x][i-1]][i-1]; lcs[x][i]=min(lcs[x][i-1],lcs[anc[x][i-1]][i-1]); } for(int i=0;i<a[x].size();i++) { int y=a[x][i].t; if(y!=anc[x][0]) { dep[y]=dep[x]+1; anc[y][0]=x; lcs[y][0]=a[x][i].l; s[++top]=y; } } while(top&&a[s[top]].size()==0)top--; } return; } int swim(int &x,int h) { int tot=inf; for(int i=0;h>0;i++) { if(h&1) { tot=min(tot,lcs[x][i]); x=anc[x][i]; } h=(h>>1); } return tot; } int lca(int x,int y) { int pos; if(dep[x]>dep[y])swap(x,y); int tot=swim(y,dep[y]-dep[x]); if(x==y)return tot; while(1) { for(pos=0;anc[x][pos]!=anc[y][pos];pos++); if(pos==0) { tot=min(lcs[y][0],tot); tot=min(lcs[x][0],tot); return tot; } tot=min(tot,lcs[x][pos-1]);x=anc[x][pos-1]; tot=min(tot,lcs[y][pos-1]);y=anc[y][pos-1]; } return -1; } int main() { ios::sync_with_stdio(false); cin>>n>>m; for(int i=1;i<=m;i++) { int x,y,z;cin>>x>>y>>z; u[i]=x;v[i]=y;w[i]=z; } for(int i=1;i<=n;i++)p[i]=i; for(int i=1;i<=m;i++)r[i]=i; sort(r+1,r+1+m,cmp); for(int i=1;i<=m;i++) { int e=r[i]; int x=find(v[e]); int y=find(u[e]); if(x!=y) { p[x]=y; edge r; r.t=v[e];r.l=w[e]; a[u[e]].push_back(r); r.t=u[e]; a[v[e]].push_back(r); } } int q;cin>>q; for(int i=1;i<=q;i++) { int x,y;cin>>x>>y; int ax=find(x); int ay=find(y); if(anc[ax][0]==0)dfs(ax); if(anc[ay][0]==0)dfs(ay); if(ax!=ay)cout<<-1<<endl; else cout<<lca(x,y)<<endl; } return 0; }
相关文章推荐
- NOIP 2013 货车运输(最大生成树+倍增LCA/Tarjan)
- noip2013货车运输
- NOIP2013货车运输 计蒜客习题 蒜头君运送宝藏
- NOIP 2013 货车运输 题解过程
- Noip2013 货车运输 - 生成树 - 倍增
- 题解 【luogu P1967 NOIp提高组2013 货车运输】
- [NOIP2013]货车运输
- NOIP2013货车运输 (最大生成树,分块求LCA)
- [NOIP 2013]货车运输
- NOIP2013day1T3----货车运输(LCA+生成树)
- noip2013 day1-3 货车运输
- noip2013货车运输(lca)
- noip2013 货车运输
- NOIP2013 货车运输 (最大生成树+树上倍增LCA)
- 洛谷 P1967 [NOIP2013 D1T3] 货车运输
- NOIP2013 货车运输 LCA倍增+最大生成树
- NOIP 2013 货车运输
- NOIP 2013 货车运输
- 洛谷—— P1967 货车运输 || COGS——C 1439. [NOIP2013]货车运输
- NOIP 2013 货车运输 TYVJ 3115