链接:http://poj.org/problem?id=1613
这题被无向边坑了很久,wa了好多次,最后从有向边改成无向边就过了。
样例解释:
2 2 1 2 1 2 5 4 10 14 20 24 30 1 2 6 2 10 22 30第一行表示:2个点,2种边,起点,终点
第二行的1 2 5表示从1到2,权值为5(当然,这是无向边,反方向也是),后面的4,10,14,20,24,30分别表示开启和关闭,这里的就是:4时刻关闭,10时刻开启,14时刻关闭,20时刻开启,24时刻关闭,30时刻开启,如果最后一个是开启的话,之后就是永久开启,最后一个是关闭的话,之后就是永久关闭,使用这个边的时候要求在进入和出去的时候都在同一个开启的时间段,比如10-14,20-24,30-INF,不能中间夹杂着关闭。输入的时候也很奇怪,我自己写了一个读入数字的,但是出错了,不知道是数据里有非法字符还是我写错了,最后用stringstream解决。
思路:
这题只给了你点和边,但是根据样例,会在相同两个点之间产生不同权值的边,所以就不能用dijkstra,所以我就想到了用bellman-ford来解决这题,只要对边进行遍历就可以求出最短路。但是这题对边的使用有时间限制,所以在松弛的时候判断一下当前这条边能否使用就可以了。
代码:
#include<stdio.h> #include<string.h> #include<vector> #include<string> #include<sstream> #include<queue> #include<cctype> #include<iostream> #include<algorithm> using namespace std; const int N=50;const int INF=1e9+10; struct Edge{ int st,to,v; vector<int> time; Edge(){} Edge(int a,int b,int c){st=a,to=b,v=c;time.clear();} }; int n,m,st,ed,d[N+10]; vector<Edge>edge; int allow(int t,int id,int vv){ vector<int> &s=edge[id].time; int i=0,flag=1;//s[0]的时候是0时刻,从0时刻开始 for(i=0;i<s.size()-1;i++,flag^=1){//用flag标记当前这条通道是开启还是关闭 if(flag&&s[i]>=t&&s[i+1]-s[i]>=vv)//两种情况,这种是在当前点停留一段时间,在下一个能通过的时间段通过 return s[i]+vv; if(flag&&s[i]<=t&&s[i+1]>=t+vv)//到达这个点的时候刚好可以使用这条边 return t+vv; } return INF;//如果不能使用这条边,返回INF } void bellman(){ fill(d,d+n+1,INF); d[st]=0; int i,j; for(i=1;i<n;i++){ bool ok=true; for(j=0;j<edge.size();j++){ int may=allow(d[edge[j].st],j,edge[j].v);//用allow函数判断当前是否能够使用这条边 if(d[edge[j].to]>may){ d[edge[j].to]=may; ok=false; } } if(ok)break; } if(d[ed]==INF)printf("*\n"); else printf("%d\n",d[ed]); } int main(){ // freopen("D://input.txt","r",stdin); while(scanf("%d",&n)!=EOF&&n){ scanf("%d%d%d",&m,&st,&ed); getchar(); edge.clear(); while(m--){ int a,b,c,x;string temp; getline(cin,temp);//读取字符串 stringstream ss(temp);//stringstream ss>>a;ss>>b;ss>>c;//输入起点,终点,权值 edge.push_back(Edge(a,b,c)); int id=edge.size()-1; edge[id].time.push_back(0);//在时间段的前后分别加上0和INF,操作起来比较方便 while(ss>>x)edge[id].time.push_back(x); edge[id].time.push_back(INF); edge.push_back(Edge(b,a,c)); id++;//无向边,所以反方向的边也要加上 for(int i=0;i<edge[id-1].time.size();i++) edge[id].time.push_back(edge[id-1].time[i]); } if(st==ed){printf("0\n");continue;} bellman(); } return 0; }