寒假,大家都回家过年去了,只有GRYZ苦逼的竞赛生们还在学校上课。众所周知,有人的地方就需要有饭,但是食堂的大爷们都回家了,我们只能依靠外卖。已知那是一个非常大的外卖店,有专业的盒饭生产设备,为了保证GRYZ的孩子们每顿饭能吃好吃的饭菜,它们总会将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
有些部门之间可能有多条传送带。
其实写这个题的过程非常坎坷,因为我不会写dij,于是,考试的时候,我先自己造了一个dij,然后出乎意料(hhh)的造错了,于是两天后(就是今天)我又认真的写(zao)了一个,但是又错了,因为我根本就不会dij。。。
然后,我开始的时候犯了这样一个**的错误
flag[1] = true; dist[1] =0; for (int i=head[1];i;i=e[i].next) dist[e[i].to] = e[i].w;
于是遇到重边重边重边啊重边重边重边就要看rp了。。。因为从1出发的边不一定扫到的最后一条就是最短啊!
实际上应该是这样的。。 (感谢世界上最机智的小敏颜!我爱小敏颜!)
dist[1] =0;
错就错在,我根本不会写dij!!!
正解:跑两个dij。
#include<iostream> #include<cstdio> #include<cstring> using namespace std; const int MAXM=100010; const int MAXN=3010; int head[MAXN]={0},head2[MAXN]={0}; int dist[MAXN]={0},dist2[MAXN]={0}; bool flag[MAXN]={false},flag2[MAXN]={false}; struct edgenode { int next,to,w; }e[MAXM],e2[MAXM]; int n,m,q,a,b,u,v,w,cnt=0,cnt2=0; void ins1(int u,int v,int w) { e[++cnt].to=v; e[cnt].next=head[u]; e[cnt].w=w; head[u] = cnt; } void ins2(int u,int v,int w) { e2[++cnt2].to=v; e2[cnt2].next=head2[u]; e2[cnt2].w=w; head2[u] = cnt2; } void dij() { memset(dist,127,sizeof(dist)); dist[1] =0; for (int j = 1; j<=n ;j++) { int minv = 10000000,k; for (int i=1;i<=n;i++) if (!flag[i] && dist[i]< minv) { minv=dist[i]; k=i; } flag[k] = true; for (int i=head[k];i;i=e[i].next) { int v = e[i].to; if (!flag[v]) { if (dist[v] > dist[k]+e[i].w) dist[v] = dist[k]+e[i].w; } } } } void dij2() { memset(dist2,127,sizeof(dist2)); dist2[1] =0; for (int j = 1; j<=n ;j++) { int minv = 10000000,k; for (int i=1;i<=n;i++) if (!flag2[i] && dist2[i]< minv) { minv=dist2[i]; k=i; } flag2[k] = true; for (int i=head2[k];i;i=e2[i].next) { int v = e2[i].to; if (!flag2[v]) { if (dist2[v] > dist2[k]+e2[i].w) dist2[v] = dist2[k]+e2[i].w; } } } } int main() { freopen("eat.in","r",stdin); freopen("eat.out","w",stdout); scanf("%d%d",&n,&m); for (int i=1;i<=m;i++) { scanf("%d%d%d",&u,&v,&w); ins1(u,v,w); ins2(v,u,w); } dij(); dij2(); scanf("%d",&q); for (int i=1;i<=q;i++) { scanf("%d%d",&a,&b); if (dist2[a]!=2139062143 && dist[b]!=2139062143) printf("%d\n",dist2[a]+dist[b]); else printf("-1\n"); } fclose(stdin); fclose(stdout); return 0; }
附上我考试的时候乱造的dij,我觉得挺有纪念意义的。。。
/*还拼错了↓。。。看看我多么认真的写了注释。。(因为造完怕自己看不懂)*/ void dijstra() { int minv = 10000000,mini=0; for (int k=1;k<=n;k++) if (vis[k]) //k的最短路已经确定 { for (int i=head[k];i;i=e[i].next) //可以用k扩展其他点。 { if (!vis[e[i].to]) if (e[i].v < minv) { minv = e[i].v; mini = i; } } } if (mini) { dist[e[mini].to]=dist[e[mini].from]+e[mini].v; //所有可行的边扩展完以后找出一个最短 vis[e[mini].to] = true; dijstra(); } } /*还写得有模有样的。。6死我了!*/
原文:http://www.cnblogs.com/liumengyue/p/5210695.html