[POI 2004]ZAW
[POI 2004]ZAW
Description
在 Byte 山的山脚下有一个洞穴入口. 这个洞穴由复杂的洞室经过隧道连接构成. 洞穴的入口是 1号点.两个洞室要么就通过隧道连接起来,要么就经过若干隧道间接的相连. 现在决定组织办一个'King's of Byteotia Cup' 比赛. 参赛者的目标就是任意选择一条路径进入洞穴并尽快出来即可. 一条路径必须经过除了 1 之外还至少要经过其他一个洞室.一条路径中一个洞不能重复经过(除了 1 以外),类似的一条隧道也不能重复经过.
一个著名的洞穴探险家 Byteala 正准备参加这个比赛. Byteala 已经训练了数月而且他已获得了洞穴系统的一套详细资料. 对于每条隧道他都详细计算了从两个方向经过所需要的时间. 经过一个洞室的时间很短可以忽略不记. 现在Byteala 向计算一条符合条件的最优路径.
Input
第一行有两个数 n 和 m (3 <= n <= 5000, 3 <= m <= 10000) 分别表示洞室的数目以及连接他们的隧道的数目. 洞室从 1 到 n 编号. “前面洞室”的编号为 1.
接下来 m 行描述了所有的隧道. 每行四个整数 a,b,c,d 表示从洞室 a 到洞室 b 需要 c分钟的时间,而从洞室 b到洞室 a需要 d分钟的时间, 1 <= a,b <= n, a <> b, 1 <= c,d <= 10000. 你可以假设符合要求的路径肯定存在.
Output
输出一行,最少需要多少时间完成比赛.
Sample Input
3 3
1 2 4 3
2 3 4 2
1 3 1 1
Sample Output
6
HINT
经过 1, 2, 3, 1
题解
要求一个最短路,担心的就是一条边被正反经过两次。
规定第一步为1到i,并把这条边设为不可经过。然后从i做最短路到1,因为这个过程是不会经历重边的(如果经历了就不是最短路了)。
数据有点坑:不要标记数组还快一点...
数据有点卡SPFA:如果松弛节点时算出的dist比之前算出的最优ans还大,显然不用拓展了。
#include<iostream> #include<cstdio> #include<cstdlib> #include<cstring> #include<cmath> #include<algorithm> #include<queue> #define inf (2000000000) using namespace std; typedef long long lol; int n,m,ans=inf; struct node { int next,to,dis; }edge[20005]; int head[5005],size=1; void putin(int from,int to,int dis) { size++; edge[size].to=to; edge[size].dis=dis; edge[size].next=head[from]; head[from]=size; } int dist[5005],vis[5005]; void SPFA(int r,int d) { memset(dist,127/3,sizeof(dist)); memset(vis,0,sizeof(vis)); queue<int>mem; mem.push(r); vis[r]=1; dist[r]=0; while(!mem.empty()) { int x=mem.front();mem.pop(); vis[x]=0; for(int i=head[x];i!=-1;i=edge[i].next) { int y=edge[i].to; if(dist[y]>dist[x]+edge[i].dis&&dist[x]+edge[i].dis+d<ans) { dist[y]=dist[x]+edge[i].dis; if(!vis[y]) { vis[y]=1; mem.push(y); } } } } } int main() { freopen("zaw.in","r",stdin); freopen("zaw.out","w",stdout); int i,j; memset(head,-1,sizeof(head)); memset(dist,127/3,sizeof(dist)); scanf("%d%d",&n,&m); for(i=1;i<=m;i++) { int from,to,dis,dist; scanf("%d%d%d%d",&from,&to,&dis,&dist); putin(from,to,dis); putin(to,from,dist); } for(i=head[1];i!=-1;i=edge[i].next) if(edge[i].dis<ans) { int dis=edge[i].dis,distt=edge[i^1].dis; edge[i].dis=inf;edge[i^1].dis=inf; SPFA(edge[i].to,dis); ans=min(ans,dis+dist[1]); edge[i].dis=dis;edge[i^1].dis=distt; } printf("%d\n",ans); return 0; }