luogu P5683 [CSPJX2019]道路拆除
题面传送门
这次\(JX\)重考的题目也太水了点吧,完全比不上原来的\(T3\)。
题目要求拆除的边数最多,那么要留下的边数最少。
那么这样的话\(1\)到\(s1\)和\(s2\)的路程中最好有一部分是重叠的。
而\(1\)到\(s1\)和\(s2\)的路程均为一条链,这两条链可能有一部分是重叠的。无论重叠也好,不重叠也好,总会有一个交点,这个交点通了至少\(2\)条路径。
所以我们可以枚举交点。
我们可以在预处理的过程中从\(1\),\(s1\)和\(s2\)各跑一遍\(SPFA\),众所周知,边权为\(1\)的图肯定卡不了\(SPFA\),所以我们可以使用。
代码实现:
#include<cstdio>
#include<cstring>
#include<queue>
using namespace std;
int n,m,k,h[5039],head,d1[5039],d2[5039],d3[5039],s1,s2,t1,t2,now,cur,x,y,z,ans=-1;
struct yyy{
int to,z;
}tmp,f[10039];
inline void add(int x,int y){
f[++head]=(yyy){y,h[x]};
h[x]=head;
}
queue<int> q;
int main(){
register int i;
scanf("%d%d",&n,&m);
memset(h,-1,sizeof(h));
memset(d1,0x3f,sizeof(d1));
memset(d2,0x3f,sizeof(d2));
memset(d3,0x3f,sizeof(d3));
for(i=1;i<=m;i++) scanf("%d%d",&x,&y),add(x,y),add(y,x);
scanf("%d%d%d%d",&s1,&t1,&s2,&t2);
d1[s1]=d2[s2]=d3[1]=0;
q.push(s1);
while(!q.empty()){
now=q.front();
q.pop();
cur=h[now];
while(cur!=-1){
tmp=f[cur];
if(d1[tmp.to]>d1[now]+1) d1[tmp.to]=d1[now]+1,q.push(tmp.to);
cur=tmp.z;
}
}
q.push(s2);
while(!q.empty()){
now=q.front();
q.pop();
cur=h[now];
while(cur!=-1){
tmp=f[cur];
if(d2[tmp.to]>d2[now]+1) d2[tmp.to]=d2[now]+1,q.push(tmp.to);
cur=tmp.z;
}
}
q.push(1);
while(!q.empty()){
now=q.front();
q.pop();
cur=h[now];
while(cur!=-1){
tmp=f[cur];
if(d3[tmp.to]>d3[now]+1) d3[tmp.to]=d3[now]+1,q.push(tmp.to);
cur=tmp.z;
}
}
for(i=1;i<=n;i++){
if(d1[i]+d3[i]<=t1&&d2[i]+d3[i]<=t2&&m-d1[i]-d2[i]-d3[i]>ans) ans=m-d1[i]-d2[i]-d3[i];
}
printf("%d\n",ans);
}