2015山东信息学夏令营 Day4T3 生产
【题目描述】
工厂为了生产一种复杂的产品,给各个生产部门制定了详细的生产计划。那么,就经常会有生产部门要把产品送到另一个生产部门作为原料。这是一个注重产品质量的工厂,所以每当有产品要从A部门运到B部门时,都要先从A部门送到质量检验处,检验合格后再从质量检验处运到B部门。
有些部门之间有传送带连接,厂长想知道每次将产品从一个部门运送到另一个部门最少需要多长时间。
【输入格式】
第一行两个整数n、m,n表示部门数量,m表示传送带数量。出于方便,1号部门是质量检验处。
接下来m行,每行三个整数u、v、w,表示有一条从u部门到v部门的传送带,传送过去需要w个单位时间。注意传送带是单向的。
接下来一个整数q,表示有q次运送。
接下来q行,每行两个数a、b,表示这一次要将产品从a部门运送到b部门。
【输出格式】
输出q行,每行一个整数,表示这次运送最少需要的时间。若没有传送方案,输出-1。
【样例输入】
5 5
1 2 3
1 3 5
4 1 7
5 4 1
5 3 1
3
4 2
5 3
2 3
【样例输出】
10
13
-1
【数据规模与约定】
30%的数据,n≤100,m≤500,w=1
60%的数据,n≤100,m≤5000
另20%的数据,q=1
100%的数据,2≤n≤3000,m≤100000,2≤a,b≤n,
q≤100000,1≤u,v≤n,1≤w≤10000
有些部门之间可能有多条传送带。
工厂的员工都非常尽职尽责,他们的认真和热情决定了产品的完美,所以不必考虑产品不合格的情况。
思路:
1、最短路,A到1再到B的距离,等于1到B的距离加上1到A的距离
2、存者正反两个图,在反图上求1到A距离,在正图上求1到B的距离
代码:
①官方标程(spfa + 链式前向星)
#include<cstdio> #include<cstring> #include<algorithm> using namespace std; const int N = 3050; const int M = 500050; const int inf = 987654321; int n,m,q; struct Edge { int u,v,w; }xu[M]; int point[N],to[M],next[M],val[M]; int dui[N],mina[N],minb[N],top,tail; bool indui[N]; void MakeMinLen(int x[]) { int i; dui[1]=1; top=0;tail=1; indui[1]=1; for(i=1;i<=n;i++) x[i]=inf; x[1]=0; while(top^tail) { top++; if(top==N) top=0; int now=dui[top]; int then=point[now]; indui[now]=0; while(then) { int tox=to[then]; if(x[tox]>x[now]+val[then]) { x[tox]=x[now]+val[then]; if(!indui[tox]) { indui[tox]=1; tail++; if(tail==N) tail=0; dui[tail]=tox; } } then=next[then]; } } } void InitGraph() { int i; scanf("%d%d",&n,&m); for(i=1;i<=m;i++) scanf("%d%d%d",&xu[i].u,&xu[i].v,&xu[i].w); memset(point,0,sizeof point); for(i=1;i<=m;i++) { next[i]=point[xu[i].v]; point[xu[i].v]=i; to[i]=xu[i].u; val[i]=xu[i].w; } MakeMinLen(mina); memset(point,0,sizeof point); for(i=1;i<=m;i++) { next[i]=point[xu[i].u]; point[xu[i].u]=i; to[i]=xu[i].v; val[i]=xu[i].w; } MakeMinLen(minb); } void MakeAns() { scanf("%d",&q); while(q--) { int a,b; scanf("%d%d",&a,&b); int res=mina[a]+minb[b]; if(res>=inf) res=-1; printf("%d\n",res); } } int main() { freopen("data.in","r",stdin); freopen("data.out","w",stdout); InitGraph(); MakeAns(); return 0; }
②自己写的,感觉dij快一点,一测发现比标程慢不少TAT
#include<iostream> #include<cstdio> #include<string> #include<cstring> #include<algorithm> #include<vector> #include<queue> #define inf ~0U>>2 #define maxn 3005 using namespace std; struct orz{ int d; int p; friend bool operator < (orz a,orz b){ return a.d > b.d; } }; struct edge{ int v; int w; }; priority_queue< orz > ss; vector<edge> g[maxn],op[maxn]; int n,m,q,flag = 0,v[maxn],d[maxn],opd[maxn]; void init(){ cin>>n>>m; int u,v,w; edge tmp; for(int i = 1;i <= m;i++){ scanf("%d%d%d",&u,&v,&w); tmp.v = v; tmp.w = w; g[u].push_back(tmp); tmp.v = u; op[v].push_back(tmp); } cin>>q; for(int i = 1;i <= n;i++) d[i] = opd[i] = inf; } void dij(){ orz tmp; tmp.d = 0; tmp.p = 1; opd[1] = 0; ss.push(tmp); flag++; int x,dd,to,wei; edge j; while(!ss.empty()){ tmp = ss.top(); ss.pop(); x = tmp.p; dd = tmp.d; if(v[x] == flag) continue; v[x] = flag; for(int i = 0;i < g[x].size();i++){ j = g[x][i]; to = j.v; wei = j.w; if(d[to] > dd + wei){ d[to] = dd + wei; tmp.d = dd + wei; tmp.p = to; ss.push(tmp); } } } } void opdij(){ orz tmp; tmp.d = 0; tmp.p = 1; opd[1] = 0; ss.push(tmp); flag++; int x,dd,to,wei; edge j; while(!ss.empty()){ tmp = ss.top(); ss.pop(); x = tmp.p; dd = tmp.d; if(v[x] == flag) continue; v[x] = flag; for(int i = 0;i < op[x].size();i++){ j = op[x][i]; to = j.v; wei = j.w; if(opd[to] > dd + wei){ opd[to] = dd + wei; tmp.d = dd + wei; tmp.p = to; ss.push(tmp); } } } } void ask(){ int u,v; long long dn; for(int i = 1;i <= q;i++){ scanf("%d%d",&u,&v); dn = opd[u] + d[v]; if(dn >= inf) cout<<-1<<endl; else cout<<dn<<endl; } } int main(){ freopen("data.in","r",stdin); freopen("data.out","w",stdout); init(); dij(); opdij(); ask(); return 0; }