题目链接:传送门
题意&题解:
1. 数从1-n排列,可以列出d[i]<=d[i+1] , 即为d[i]-d[i+1]<=0,可建立 i+1 到 i 的有向边,权值为0
2. 给出ML行 A,B和N,表示a和b的距离不能超过N,可以列出 d[B]-d[A]<=D, 即为 d[B]-d[A]<= D,可建立A到B的有向边,权值为D
3. 给出MD行 A,B和N,表示a和b的距离不能少于N,可以列出d[B]-d[A]>=D ,即为 d[A]-d[B]<= -D,可建立B到A的有向边,权值为-D
最后跑一边spfa计算从1-n的最短路径
代码:用链式前向星存图跑完超时,后来发现数组少加了n个边,加上就过了,注意多测试用例要改掉。
链式前向星&spfa:
#include<vector> #include<cstdio> #include<iostream> #include<cmath> #include<queue> #define numm ch-48 #define pd putchar(' ') #define pn putchar('\n') #define pb push_back #define fi first #define se second #define fre1 freopen("1.txt","r",stdin) #define fre2 freopen("2.txt","w",stdout) using namespace std; template <typename T> void read(T &res) { bool flag=false;char ch; while(!isdigit(ch=getchar())) (ch=='-')&&(flag=true); for(res=numm;isdigit(ch=getchar());res=(res<<1)+(res<<3)+numm); flag&&(res=-res); } template <typename T> void write(T x) { if(x<0) putchar('-'),x=-x; if(x>9) write(x/10); putchar(x%10+'0'); } const int maxn=110; const int N=1010; const int M=10010; const int inf=0x3f3f3f3f; typedef long long ll; struct edge { int to,w,net; }edge[M+N]; int k,dis[N]; int sum[N],head[N],vis[N]; int que[M<<1]; void init(int n) { k=0; for(int i=1;i<=n;i++) head[i]=-1,vis[i]=false,sum[i]=0,dis[i]=inf; } void add(int u,int v,int w) { edge[++k].to=v; edge[k].w=w; edge[k].net=head[u]; head[u]=k; } int spfa(int n) { ++sum[1],dis[1]=0; queue<int>que; que.push(1); while(!que.empty()) { int u=que.front(); que.pop(); vis[u]=false; for(int i=head[u];i!=-1;i=edge[i].net) { int v=edge[i].to; if(dis[v]>dis[u]+edge[i].w) { dis[v]=dis[u]+edge[i].w; if(!vis[v]) { if(++sum[v]>n) return -1; vis[v]=true; que.push(v); } } } } return dis[n]==inf ? -2 : dis[n]; } int main() { int n,ml,md; while(scanf("%d%d%d",&n,&ml,&md)!=EOF) { init(n); for(int i=1;i<=ml;i++) { /// d[B]-d[A]<=D int a,b,d; read(a),read(b),read(d); add(a,b,d); } for(int i=1;i<=md;i++) { /// d[A]-d[B]<=-D int a,b,d; read(a),read(b),read(d); add(b,a,-d); } for(int i=1;i<n;i++) /// d[i]-d[i+1]<=0 add(i+1,i,0); write(spfa(n));pn; } return 0; }
动态邻接表&spfa:
#include<vector> #include<cstdio> #include<iostream> #include<cmath> #include<queue> #define numm ch-48 #define pd putchar(' ') #define pn putchar('\n') #define pb push_back #define fi first #define se second #define fre1 freopen("1.txt","r",stdin) #define fre2 freopen("2.txt","w",stdout) using namespace std; template <typename T> void read(T &res) { bool flag=false;char ch; while(!isdigit(ch=getchar())) (ch=='-')&&(flag=true); for(res=numm;isdigit(ch=getchar());res=(res<<1)+(res<<3)+numm); flag&&(res=-res); } template <typename T> void write(T x) { if(x<0) putchar('-'),x=-x; if(x>9) write(x/10); putchar(x%10+'0'); } const int maxn=110; const int N=1010; const int M=10010; const int inf=0x3f3f3f3f; typedef long long ll; struct edge{ int v,w; }; vector<edge>e[N]; int sum[N],vis[N],dis[N]; int spfa(int n) { sum[1]++; dis[1]=0; queue<int>que; que.push(1); while(!que.empty()) { int u=que.front();que.pop(); vis[u]=false; for(int i=0;i<e[u].size();i++) { edge x=e[u][i]; int v=x.v; if(dis[v]>dis[u]+x.w) { dis[v]=dis[u]+x.w; if(!vis[v]) { if(++sum[v] > n) return -1; que.push(v); vis[v] = true; } } } } return dis[n]==inf ? -2 : dis[n]; } int main() { int n,ml,md; while(scanf("%d%d%d",&n,&ml,&md)!=EOF) { for(int i=1;i<=n;i++) vis[i]=false,dis[i]=inf,sum[i]=0,e[i].clear(); for(int i=1;i<=ml;i++){ /// d[B]-d[A]<=D int a,b,d; read(a),read(b),read(d); e[a].pb((edge){b,d}); } for(int i=1;i<=md;i++) { /// d[A]-d[B]<=-D int a,b,d; read(a),read(b),read(d); e[b].pb((edge){a,-d}); } for(int i=1;i<n;i++) /// d[i]-d[i+1]<=0 e[i+1].pb((edge){i,0}); write(spfa(n)),pn; } return 0; }