算法:SPFA+SLF
思路:
- 差分约束,详见AndyZhang的BLOG。注意是可以直接建造负权路径的。
- 发现负环,则是无解;dis[N]==INF,则是无穷解;有唯一解(本题中为最短路)输出 dis[N]。
- 终于成功用SLF优化了SPFA!降低到了16ms。
- 而且:LLL根本不优化,反而会降速到63ms。
代码:
#include <iostream>
#include <queue>
#include <cstring>
#include <cstdio>
#define INF 0x3f3f3f3f
using namespace std;
const int maxn = 1005;
int N,ML,MD;
int dis[maxn];
struct EDGE{
int to;
int w;
int fo;
}E[maxn * 20] ;int cnt=0;
int tail[maxn];
void ADDEDGE(int u,int v,int w){
++cnt;
E[cnt].to = v;
E[cnt].w = w;
E[cnt].fo = tail[u];
tail[u] = cnt;
return ;
}
queue<int> q;
int rec[maxn];
bool enq[maxn];
int SPFA(){
memset(dis,INF,sizeof(dis));
memset(rec, 0 ,sizeof(rec));
memset(enq, 0 ,sizeof(enq));
q.push(1);dis[1]=0;enq[1]=true;rec[1]=1;
while(q.size()){
int cur = q.front() ; q.pop() ; enq[cur] = false;
for(int i=tail[cur] ; ~i ; i=E[i].fo){
int v = E[i].to;
if(dis[v] > dis[cur] + E[i].w){
dis[v] = dis[cur] + E[i].w;
if(!enq[v]){
q.push(v);
rec[v]++;
enq[v] = true;
if(rec[v] == N)
return -1;
}
}
}
}
return dis[N] == INF ? -2 : dis[N] ;
}
int main(){
scanf("%d%d%d",&N,&ML,&MD);
memset(tail , -1 , sizeof(tail));
while(ML--){
int u,v,w;
scanf("%d%d%d",&u,&v,&w);
ADDEDGE(u,v,w);
}
while(MD--){
int u,v,w;
scanf("%d%d%d",&u,&v,&w);
ADDEDGE(v,u,-w);
}
printf("%d\n",SPFA());
return 0;
}
#include <iostream>
#include <queue>
#include <cstring>
#include <cstdio>
#define INF 0x3f3f3f3f
using namespace std;
const int maxn = 1005;
int N,ML,MD;
int dis[maxn];
struct EDGE{
int to;
int w;
int fo;
}E[maxn * 20] ;int cnt=0;
int tail[maxn];
void ADDEDGE(int u,int v,int w){
++cnt;
E[cnt].to = v;
E[cnt].w = w;
E[cnt].fo = tail[u];
tail[u] = cnt;
return ;
}
deque<int> q;
int rec[maxn];
bool enq[maxn];
int SPFA(){
memset(dis,INF,sizeof(dis));
memset(rec, 0 ,sizeof(rec));
memset(enq, 0 ,sizeof(enq));
q.push_front(1);dis[1]=0;enq[1]=true;rec[1]=1;
while(q.size()){
int cur = q.front() ; q.pop_front() ; enq[cur] = false;
for(int i=tail[cur] ; ~i ; i=E[i].fo){
int v = E[i].to;
if(dis[v] > dis[cur] + E[i].w){
dis[v] = dis[cur] + E[i].w;
if(!enq[v]){
if(q.size() && dis[v] > dis[q.front()])
q.push_back(v);
else
q.push_front(v);
rec[v]++;
enq[v] = true;
if(rec[v] == N)
return -1;
}
}
}
}
return dis[N] == INF ? -2 : dis[N] ;
}
int main(){
scanf("%d%d%d",&N,&ML,&MD);
memset(tail , -1 , sizeof(tail));
while(ML--){
int u,v,w;
scanf("%d%d%d",&u,&v,&w);
ADDEDGE(u,v,w);
}
while(MD--){
int u,v,w;
scanf("%d%d%d",&u,&v,&w);
ADDEDGE(v,u,-w);
}
printf("%d\n",SPFA());
return 0;
}
#include <iostream>
#include <queue>
#include <cstring>
#include <cstdio>
#define INF 0x3f3f3f3f
using namespace std;
const int maxn = 1005;
int N,ML,MD;
int dis[maxn];
struct EDGE{
int to;
int w;
int fo;
}E[maxn * 20] ;int cnt=0;
int tail[maxn];
void ADDEDGE(int u,int v,int w){
++cnt;
E[cnt].to = v;
E[cnt].w = w;
E[cnt].fo = tail[u];
tail[u] = cnt;
return ;
}
deque<int> q;
int rec[maxn];
bool enq[maxn];
int SPFA(){
int sum=0;
int num ;
memset(dis,INF,sizeof(dis));
memset(rec, 0 ,sizeof(rec));
memset(enq, 0 ,sizeof(enq));
q.push_front(1);dis[1]=0;enq[1]=true;rec[1]=1;
while(num = q.size()){
int cur = q.front() ; q.pop_front();
while(dis[cur] * num > sum){
q.push_back(cur);
cur = q.front() ; q.pop_front() ;
}
sum -= dis[cur];enq[cur]=false;
for(int i=tail[cur] ; ~i ; i=E[i].fo){
int v = E[i].to;
if(dis[v] > dis[cur] + E[i].w){
dis[v] = dis[cur] + E[i].w;
if(!enq[v]){
q.push_front(v);
sum += dis[v];
rec[v]++;
enq[v] = true;
if(rec[v] == N)
return -1;
}
}
}
}
return dis[N] == INF ? -2 : dis[N] ;
}
int main(){
scanf("%d%d%d",&N,&ML,&MD);
memset(tail , -1 , sizeof(tail));
while(ML--){
int u,v,w;
scanf("%d%d%d",&u,&v,&w);
ADDEDGE(u,v,w);
}
while(MD--){
int u,v,w;
scanf("%d%d%d",&u,&v,&w);
ADDEDGE(v,u,-w);
}
printf("%d\n",SPFA());
return 0;
}