您的位置:首页 > 其它

NOIP2013货车运输

2016-10-06 18:02 246 查看
题目来源https://www.luogu.org/problem/show?pid=1967

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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: