简要题意
给你一个 \(m\) 条边 \(n\) 个点的无向图。你需要去掉一些边,使得 \(1 \to s_1,1 \to s_2\) 连通,且 \(1 \to s_1\) 的最短路径长度小于 \(t_1\),\(1 \to s_2\) 的最短路径长度小于 \(t_2\)。求去掉的边的最大数量。如果无解,输出 \(-1\)。
对于 \(100\%\) 的数据,\(2 \le n,m \le 3000\),\(1\le x,y \le n\),\(2 \le s_1,s_2 \le n\),\(0 \le t_1,t_2 \le n\)。
思路
不难发现,最后答案就是一个树,类似:
- ... - s1
1 - ...- A
- ... - s2
就是带重叠的 \(1 \to s_1\) 和 \(1 \to s_2\) 两条最短路径。
那么剩下的就是枚举 \(A\) 节点。先求以 \(1,s_1,s_2\) 三个节点为源点的单源最短路,然后枚举 \(A\)。然后找满足条件的最小值即可。
使用 BFS 求单源最短路,总时间复杂度 \(O(n)\)。
代码
#include <bits/stdc++.h>
#define int long long
using namespace std;
int n,m,s1,t1,s2,t2,ans=-INT_MAX;
struct edge{
int nxt,to;
} g[6005];
int head[3005],ec;
void add(int u,int v){
g[++ec].nxt=head[u];
g[ec].to=v;
head[u]=ec;
}
int dis[5][3005];
queue<int> q;
void bfs(int s,int tag){
memset(dis[tag],0x3f,sizeof(dis[tag]));
dis[tag][s]=0;
q.push(s);
while(!q.empty()){
int u = q.front();
q.pop();
for(int i=head[u];i;i=g[i].nxt){
int v=g[i].to;
if((dis[tag][u]+1)<dis[tag][v]){
dis[tag][v]=dis[tag][u]+1;
q.push(v);
}
}
}
}
signed main(){
cin>>n>>m;
for(int i=1,x,y;i<=m;i++){
cin>>x>>y;
add(x,y);add(y,x);
}
cin>>s1>>t1>>s2>>t2;
bfs(1,0);
bfs(s1,1);
bfs(s2,2);
for(int center=1;center<=n;center++){
if((dis[0][center]+dis[1][center])<=t1 && (dis[0][center]+dis[2][center])<=t2){
ans=max(ans,m-(dis[0][center]+dis[1][center]+dis[2][center]));
}
}
if(ans<-1e9)cout<<-1;
else cout<<ans;
return 0;
}
标签:le,int,ec,P5683,bfs,tag,J2019,CSP,dis
From: https://www.cnblogs.com/zheyuanxie/p/p5683.html