题意:输入n个点,m条无向边(n,m<3000),接着输入s1, t1, l1, s2, t2, l2问最多可以删多少条边,使得s1到t1距离最多为l1, s2到t2距离最多为l2
题解:可以发现有三种情况
第一种是不可能情况
第二种是s1->t1, s2->t2没有重复的边,那么答案就是m-(d[s1][t1]+d[s2][t2])
第三种是有重复的边,这时候会形成一个类似H形状的图,只要枚举中间重复的边,计算答案就可以
注意这里不能用floyed来算最短路,O(n^3),因为边较少且为正,可以n次dijstra, 复杂度O(VE + V*V*logV)
或者n次bfs也可以
#include <bits/stdc++.h> #define maxn 3010 #define INF 0x3f3f3f3f typedef long long ll; using namespace std; struct edge{ int from,to,dist; }; struct node{ int d,u; bool operator<(const node& a) const{ return d>a.d; } }; int d[maxn][maxn]; struct dij{ int n,m; vector<int >G[maxn]; vector<edge>edges; bool done[maxn]; int p[maxn]; void init(int x){ n = x; for(int i=1;i<=n;i++) G[i].clear(); edges.clear(); } void add(int a,int b,int w){ edges.push_back((edge){a,b,w}); m = edges.size(); G[a].push_back(m-1); } void dijstra(int st){//计算最短路 for(int i=1;i<=n;i++) d[st][i] = INF; memset(done, 0, sizeof(done)); d[st][st] = 0; priority_queue<node>q; q.push((node){0, st}); while(!q.empty()){ node fi = q.top();q.pop(); int u = fi.u; if(done[u]) continue; done[u] = 1; for(int i=0;i<G[u].size();i++){ edge& e = edges[G[u][i]]; if(e.dist+d[st][u]<d[st][e.to]){ d[st][e.to] = d[st][u]+e.dist; p[e.to] = G[u][i]; q.push((node){d[st][e.to], e.to}); } } } } }dj; int main(){ int n, m, a, b, s1, t1, l1, s2, t2, l2; scanf("%d%d", &n, &m); dj.init(n); for(int i=0;i<m;i++){ scanf("%d%d", &a, &b); dj.add(a, b, 1); dj.add(b, a, 1); } scanf("%d%d%d", &s1, &t1, &l1); scanf("%d%d%d", &s2, &t2, &l2); for(int i=1;i<=n;i++) dj.dijstra(i); if(d[s1][t1] > l1||d[s2][t2] > l2) printf("-1 "); else{ int ans = d[s1][t1]+d[s2][t2]; for(int i=1;i<=n;i++){ for(int j=1;j<=n;j++){ if(d[s1][i]+d[i][j]+d[j][t1]<=l1&&d[s2][i]+d[i][j]+d[j][t2]<=l2) ans = min(ans, d[i][j]+d[s1][i]+d[j][t1]+d[s2][i]+d[j][t2]); if(d[s1][i]+d[i][j]+d[j][t1]<=l1&&d[s2][j]+d[j][i]+d[i][t2]<=l2) ans = min(ans, d[i][j]+d[s1][i]+d[j][t1]+d[s2][j]+d[i][t2]); } } printf("%d ", m-ans); } return 0; }