背景:(Codeforces) (Round) (#302) ((Div. 1)) (B) 题, (Codeforces543B)
给定一张边权全为 (1) 的图。在保证点 (s_1) 到点 (t_1) 的距离不超过 (l_1) 且点 (s_2) 到点 (t_2) 的距离不超过 (l_2) 的条件下,求最多能删去的边数。如果没有合法方案,输出 (-1) 。
这题最关键的就是转化模型。一开始我死都没想到正解就是因为忽略了边权全为 (1) 。
设点 (i) 到点 (j) 的最短长度为 (dis[i][j]) 。这时原条件就可以转化成求点 (s_1) 到点 (t_1) 的最短路上和点 (s_2) 到点 (t_2) 的最短路上经过的路径边数之和。
当然,这其中有 (3) 种情况:
第一种是点 (s_1) 到点 (t_1) 的最短路和点 (s_2) 到点 (t_2) 的最短路没有重叠部分。这个时候两个最短路值直接相加就行。
第二种是点 (s_1) 到点 (t_1) 的最短路和点 (s_2) 到点 (t_2) 的最短路在点 (i) 和点 (j) 之间重叠。这个时候可以 (O(n^2)) 枚举重叠点 (i) 和 (j) ,在保证路长限制的情况下更新答案就行,答案是 (dis[s_1][i]+dis[s_2][i]+dis[i][j]+dis[j][t_1]+dis[j][t_2]) 。
第三种也是点 (s_1) 到点 (t_1) 的最短路和点 (s_2) 到点 (t_2) 的最短路在点 (i) 和点 (j) 之间重叠,但是点 (s_2) 到点 (t_2) 的最短路从点 (i) 走向点 (j) ,而点 (s_1) 到点 (t_1) 的最短路从点 (j) 走向点 (i) 。 这个时候做法同上,答案是 (dis[s_1][j]+dis[s_2][i]+dis[i][j]+dis[i][t_1]+dis[j][t_2]) 。
至于求任意两点的最短路嘛,做 (n) 遍 (bfs) 就行。
整个过程就是这样,如果还有什么不明白的,评论区见!感谢您的耐心阅读!
代码如下:
#include<bits/stdc++.h>
using namespace std;
inline int read()
{
int ret=0,f=1;
char ch=getchar();
while(ch>'9'||ch<'0')
{
if(ch=='-')
f=-1;
ch=getchar();
}
while(ch>='0'&&ch<='9')
{
ret=(ret<<1)+(ret<<3)+ch-'0';
ch=getchar();
}
return ret*f;
}
int n,m,x,y,s1,s2,t1,t2,l1,l2,ans;
int num,head[6005],dis[3005][3005],vis[3005];
struct edge
{
int ver,nxt;
}e[6005];
queue<int> q;
inline void adde(int u,int v)
{
e[++num].ver=v;
e[num].nxt=head[u];
head[u]=num;
}
inline void bfs(int s)
{
memset(vis,0,sizeof(vis));
q.push(s);
vis[s]=1;
while(!q.empty())
{
int x=q.front();
q.pop();
for(register int i=head[x];i;i=e[i].nxt)
{
int y=e[i].ver;
if(vis[y])
continue;
vis[y]=1;
dis[s][y]=dis[s][x]+1;
q.push(y);
}
}
}
int main()
{
n=read();
m=read();
for(register int i=1;i<=m;i++)
{
x=read();
y=read();
adde(x,y);
adde(y,x);
}
for(register int i=1;i<=n;i++)
bfs(i);
s1=read();
t1=read();
l1=read();
s2=read();
t2=read();
l2=read();
if(dis[s1][t1]>l1||dis[s2][t2]>l2)
{
printf("-1
");
return 0;
}
ans=dis[s1][t1]+dis[s2][t2];
for(register int i=1;i<=n;i++)
{
for(register int j=1;j<=n;j++)
{
if(dis[s1][i]+dis[i][j]+dis[j][t1]<=l1&&dis[s2][i]+dis[i][j]+dis[j][t2]<=l2)
ans=min(ans,dis[s1][i]+dis[i][j]+dis[j][t1]+dis[s2][i]+dis[j][t2]);
if(dis[s1][j]+dis[i][j]+dis[i][t1]<=l1&&dis[s2][i]+dis[i][j]+dis[j][t2]<=l2)
ans=min(ans,dis[s1][j]+dis[i][j]+dis[i][t1]+dis[s2][i]+dis[j][t2]);
}
}
printf("%d
",m-ans);
return 0;
}