题目链接:传送门
题意&题解:
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;
}