一个有向图,s为起点,t为终点,问每条边是否在唯一的最短路上。
对s和t分别求一次单源最短路(dijkstra),顺便记录方案数。然后对每条边检查,长度符合的话,就说明在最短路上,如果方案数也符合,就是唯一的。这个方案数可能很大,所以需要取模,并靠人品AC(1e9+7被卡掉了)。
#include <bits/stdc++.h>
using namespace std;
#define ll long long
const int maxn = 100010;
const int maxm = 100010;
const ll INF = 1e12;
const ll mod = 1e9+13;
int n,m,s,t;
int head[maxn];
int pre[maxm];
int _head[maxn];
int _pre[maxm];
int cnt;
void init(){
memset(head,-1,sizeof(head));
memset(_head,-1,sizeof(_head));
cnt=1;
}
void addedge(int u,int v){
pre[cnt]=head[u];
head[u]=cnt;
_pre[cnt]=_head[v];
_head[v]=cnt;
cnt++;
}
int a[maxm];
int b[maxm];
int l[maxm];
ll dist_s[maxn];
ll dist_t[maxn];
ll way_s[maxn];
ll way_t[maxn];
bool vis[maxn];
struct node{
int u;
ll dist;
node(int u,ll dist):u(u),dist(dist){}
node(){}
bool operator<(const node &other)const{
return dist>other.dist;
}
};
void dijkstra(int s,ll *d,ll *w,int *head,int *pre){
for(int i=1;i<=n;i++){
d[i]=INF;
}
w[s]=1;
d[s]=0;
priority_queue<node> pq;
pq.push(node(s,0));
while(pq.size()){
node cur = pq.top(); pq.pop();
if(vis[cur.u])continue;
for(int i=head[cur.u];i!=-1;i=pre[i]){
int v=b[i];
ll tmp=d[v];
if(d[cur.u]+l[i]<d[v]){
w[v]=w[cur.u];
tmp=d[cur.u]+l[i];
d[v]=tmp;
pq.push(node(v,tmp));
}else if(d[cur.u]+l[i]==d[v]){
w[v]+=w[cur.u];
d[v]=tmp;
}
w[v]%=mod;
}
vis[cur.u]=1;
}
}
int main(){
init();
cin>>n>>m>>s>>t;
for(int i=1;i<=m;i++){
scanf("%d%d%d",&a[i],&b[i],&l[i]);
addedge(a[i],b[i]);
}
dijkstra(s,dist_s,way_s,head,pre);
for(int i=1;i<=m;i++)swap(a[i],b[i]);
memset(vis,0,sizeof(vis));
dijkstra(t,dist_t,way_t,_head,_pre);
for(int i=1;i<=m;i++)swap(a[i],b[i]);
for(int i=1;i<=m;i++){
ll need = dist_s[a[i]]+dist_t[b[i]]+l[i] - dist_s[t];
if(0==need && (way_s[a[i]]*way_t[b[i]])%mod==way_s[t] ){
printf("YES\n");
}else{
if(l[i]-need-1>0){
printf("CAN %I64d\n",need+1);
}else{
printf("NO\n");
}
}
}
return 0;
}
不管怎么说,取mod的方法只能人品AC,正解应该是找桥,在最短路上的桥是YES,其他是CAN。要注意重边的问题。。
另外,我有一个疑惑,问什么资料上的tarjan喜欢用dfn更新low。。如果都用low更新,不是更简洁,统一吗。求大神解答。。
#include <bits/stdc++.h>
using namespace std;
#define ll long long
const int maxn = 100010;
const int maxm = 100010;
const ll INF = 1e12;
int n,m,s,t;
int a[maxm];
int b[maxm];
int l[maxm];
ll dist_s[maxn];
ll dist_t[maxn];
bool vis[maxn];
int head[maxn];
int pre[maxm];
int _head[maxn];
int _pre[maxm];
int cnt;
int dfn[maxn];
int low[maxn];
int dfstime;
int sta[maxn];
int statop;
struct Edge{
int v;
int id;
}edge[maxm<<1];
int sphead[maxn];
int sppre[maxm<<1];
bool isUnique[maxm];
void init(){
memset(head,-1,sizeof(head));
memset(_head,-1,sizeof(_head));
memset(sphead,-1,sizeof(sphead));
cnt=1;
dfstime=0;
statop=0;
}
void addedge(int u,int v){
pre[cnt]=head[u];
head[u]=cnt;
_pre[cnt]=_head[v];
_head[v]=cnt;
cnt++;
}
struct node{
int u;
ll dist;
node(int u,ll dist):u(u),dist(dist){}
node(){}
bool operator<(const node &other)const{
return dist>other.dist;
}
};
void dijkstra(int s,ll *d,int *head,int *pre){
for(int i=1;i<=n;i++){
d[i]=INF;
}
d[s]=0;
priority_queue<node> pq;
pq.push(node(s,0));
while(pq.size()){
node cur = pq.top(); pq.pop();
if(vis[cur.u])continue;
for(int i=head[cur.u];i!=-1;i=pre[i]){
int v=b[i];
ll tmp=d[v];
if(d[cur.u]+l[i]<d[v]){
tmp=d[cur.u]+l[i];
d[v]=tmp;
pq.push(node(v,tmp));
}else if(d[cur.u]+l[i]==d[v]){
d[v]=tmp;
}
}
vis[cur.u]=1;
}
}
void addsp(int u,int v,int id){
edge[cnt].v=v; edge[cnt].id=id;
sppre[cnt]=sphead[u];
sphead[u]=cnt++;
edge[cnt].v=u; edge[cnt].id=id;
sppre[cnt]=sphead[v];
sphead[v]=cnt++;
}
void tarjan(int u,int fa){
dfn[u]=dfstime;
low[u]=dfstime++;
sta[statop++]=u;
vis[u]=1;
for(int i=sphead[u];i!=-1;i=sppre[i]){
int v=edge[i].v;
if((i^1)==fa)continue;
if(!vis[v]){
tarjan(v,i);
}
low[u]=min(low[u],low[v]);
if(low[v]>dfn[u]){
isUnique[edge[i].id]=1;
while(statop>0){
int cur=sta[--statop];
if(cur==u)break;
}
}
}
}
int main(){
init();
cin>>n>>m>>s>>t;
for(int i=1;i<=m;i++){
scanf("%d%d%d",&a[i],&b[i],&l[i]);
addedge(a[i],b[i]);
}
dijkstra(s,dist_s,head,pre);
for(int i=1;i<=m;i++)swap(a[i],b[i]);
memset(vis,0,sizeof(vis));
dijkstra(t,dist_t,_head,_pre);
for(int i=1;i<=m;i++)swap(a[i],b[i]);
cnt=0;
memset(vis,0,sizeof(vis));
for(int i=1;i<=m;i++){
ll need = dist_s[a[i]]+dist_t[b[i]]+l[i] - dist_s[t];
if(0==need){
addsp(a[i],b[i],i);
}
}
tarjan(s,-1);
for(int i=1;i<=m;i++){
ll need = dist_s[a[i]]+dist_t[b[i]]+l[i] - dist_s[t];
if(isUnique[i]){
printf("YES\n");
}else{
if(l[i]-need-1>0){
printf("CAN %I64d\n",need+1);
}else{
printf("NO\n");
}
}
}
return 0;
}