【NOIP 校內模擬】T2 規避(容斥+最短路計數)
阿新 • • 發佈:2018-12-30
可以先不管符合條件的 先統計出所有的可能走法(最短路條數*最短路條數) 然後減去會相遇的
會相遇的分為在點相遇和在邊相遇
在點(設為p)相遇:先保證點在最短路上 然後從s到p的最短路等於從t到p的最短路
在邊(設為(x,y,z))相遇:同樣需要保證邊在最短路上(需要判斷三次 同樣玄妙♂) 以及相遇的地方一定在邊上(兩條不同的最短路的兩倍不超過總長 這個姿♂勢可以記住) 挺玄妙的
#include<bits/stdc++.h> #define mod 1000000007 #define N 100005 #define M 200005 #define INF 0x3f3f3f3f #define ll long long using namespace std; template<class T> inline void read(T &x) { x=0; int f=1; static char ch=getchar(); while((!isdigit(ch))&&ch!='-') ch=getchar(); if(ch=='-') f=-1,ch=getchar(); while(isdigit(ch)) x=x*10+ch-'0',ch=getchar(); x*=f; } struct Edge { int from,to,next; ll val; }edge[2*M],res[2*M]; int n,m,first[N],tot,s,t; inline void addedge(int x,int y,int z) { tot++; edge[tot].from=x; edge[tot].to=y; edge[tot].next=first[x]; edge[tot].val=z; first[x]=tot; } typedef pair<ll,int> Pair; ll cnt[N][3],dis[N][3]; int visit[N]; void dijkstra(int S,int f) { memset(visit,0,sizeof(visit)); priority_queue<Pair,vector<Pair>,greater<Pair> > heap; heap.push(make_pair(0,S)); dis[S][f]=0; cnt[S][f]=1; while(!heap.empty()) { int now=heap.top().second; heap.pop(); if(visit[now]) continue; visit[now]=1; for(int u=first[now];u;u=edge[u].next) { int vis=edge[u].to; if(dis[now][f]+edge[u].val<dis[vis][f]) { cnt[vis][f]=cnt[now][f]; dis[vis][f]=dis[now][f]+edge[u].val; heap.push(make_pair(dis[vis][f],vis)); } else if(dis[now][f]+edge[u].val==dis[vis][f]) cnt[vis][f]=(cnt[vis][f]+cnt[now][f])%mod; } } } int main() { // freopen("evade.in","r",stdin); read(n),read(m),read(s),read(t); for(int i=1,x,y,z;i<=m;i++) { read(x),read(y),read(z); addedge(x,y,z); addedge(y,x,z); } memset(dis,0x3f,sizeof(dis)); dijkstra(s,1); dijkstra(t,2); ll ans=cnt[t][1]*cnt[t][1]%mod,len=dis[t][1]; //總方案數 for(int i=1;i<=n;i++) //先判斷點 { if(dis[i][1]+dis[i][2]!=len) continue; //不在最短路上 if(dis[i][1]==dis[i][2]) { ans=((ans-cnt[i][1]*cnt[i][1]%mod*cnt[i][2]*cnt[i][2]%mod)%mod+mod)%mod; continue; } if(dis[i][1]*2>=len) continue; //保證在邊上 for(int u=first[i];u;u=edge[u].next) { int vis=edge[u].to; if(dis[vis][2]*2>=len) continue; if(len!=dis[i][1]+edge[u].val+dis[vis][2]) continue; //不在最短路上 ans=((ans-cnt[i][1]*cnt[vis][2]%mod*cnt[i][1]*cnt[vis][2]%mod)%mod+mod)%mod; } } cout<<(ans%mod+mod)%mod; return 0; }