题意:
有n个点,m条边,每条边的长度为1,给出s1,t1,l1表示s1到t1点路径长度不能超过l1,同理对于s2,t2,l2
现要求满足条件下,最多能删多少条边
思路:
删去最多的边,就是要用最少的边,所有s1->t1和s2->t2要在满足各自要求的前提下,尽可能多的共用一些边
由于n<=3000,可以用spfa在O(n^2)的时间内预处理出任意两点间的最短路
然后枚举共用边O(n^2)
dist[s1][i]+dist[i][j]+dist[j][t1]<=l1 && dist[s2][i]+dist[i][j]+dsit[j][t2]<=l2 若满足此条件,
则尝试更新答案,ans=min(ans,dist[s1][i]+dist[i][j]+dist[j][t1]+dist[s2][i]+dist[j][t2]) dist[i][j]被用了两次,但只需记录一次
因为题中并未说明这几个点之间的方向关系,所以可能存在共用一条边但方向不同的情况,所以还要枚举所有方向
dist[s1][i]+dist[i][j]+dist[j][t1]<=l1 && dist[s2][i]+dist[i][j]+dsit[j][t2]<=l2
ans=min(ans,dist[s1][i]+dist[i][j]+dist[j][t1]+dist[s2][i]+dist[j][t2])
dist[s1][i]+dist[i][j]+dist[j][t1]<=l1 && dist[s2][j]+dist[j][i]+dsit[i][t2]<=l2
ans=min(ans,dist[s1][i]+dist[i][j]+dist[j][t1]+dist[s2][i]+dist[j][t2])
dist[s1][j]+dist[j][i]+dist[i][t1]<=l1 && dist[s2][i]+dist[i][j]+dsit[j][t2]<=l2
ans=min(ans,dist[s1][i]+dist[i][j]+dist[j][t1]+dist[s2][i]+dist[j][t2])
dist[s1][j]+dist[j][i]+dist[i][t1]<=l1 && dist[s2][j]+dist[j][i]+dsit[i][t2]<=l2
ans=min(ans,dist[s1][i]+dist[i][j]+dist[j][t1]+dist[s2][i]+dist[j][t2])
代码:
#include <iostream>
#include <cstring>
#include <queue>
using namespace std;
const int maxn=3005;
const int INF=0x3f3f3f3f;
struct node
{
int to,next,cost;
}e[4*maxn];
int p[maxn],eid;
void init()
{
eid=0;
memset(p,-1,sizeof(p));
}
void insert(int u,int v)
{
e[eid].to=v;
e[eid].cost=1;
e[eid].next=p[u];
p[u]=eid++;
}
void addedge(int u,int v)
{
insert(u,v);
insert(v,u);
}
int dist[maxn][maxn];
bool vis[maxn];
int n,m;
void spfa(int s)
{
memset(vis,0,sizeof(vis));
for(int i=1;i<=n;i++)
dist[s][i]=INF;
dist[s][s]=0;
queue<int>Q;
Q.push(s);
while(!Q.empty())
{
int u=Q.front();
Q.pop();
vis[u]=false;
for(int i=p[u];i!=-1;i=e[i].next)
{
int v=e[i].to;
if(dist[s][v]>dist[s][u]+1)
{
dist[s][v]=dist[s][u]+1;
if(!vis[v])
{
vis[v]=true;
Q.push(v);
}
}
}
}
}
int main()
{
std::ios::sync_with_stdio(false);
cin>>n>>m;
init();
for(int i=0;i<m;i++)
{
int u,v;
cin>>u>>v;
addedge(u,v);
}
for(int i=1;i<=n;i++) //预处理出任意两点间最短路
{
spfa(i);
}
int s1,t1,s2,t2,l1,l2;
cin>>s1>>t1>>l1;
cin>>s2>>t2>>l2;
int ans=dist[s1][t1]+dist[s2][t2];
for(int i=1;i<=n;i++) //枚举共用点,包含不同方向
for(int j=1;j<=n;j++)
{
if(dist[s1][i]+dist[i][j]+dist[j][t1]<=l1 && dist[s2][i]+dist[i][j]+dist[j][t2] <=l2)
ans=min(ans,dist[s1][i]+dist[i][j]+dist[j][t1]+dist[s2][i]+dist[j][t2]);
if(dist[s1][i]+dist[i][j]+dist[j][t1]<=l1 && dist[s2][j]+dist[j][i]+dist[i][t2] <=l2)
ans=min(ans,dist[s1][i]+dist[i][j]+dist[j][t1]+dist[s2][j]+dist[i][t2]);
if(dist[s1][j]+dist[j][i]+dist[i][t1]<=l1 && dist[s2][i]+dist[i][j]+dist[j][t2] <=l2)
ans=min(ans,dist[s1][j]+dist[i][j]+dist[i][t1]+dist[s2][i]+dist[j][t2]);
if(dist[s1][j]+dist[j][i]+dist[i][t1]<=l1 && dist[s2][j]+dist[j][i]+dist[i][t2] <=l2)
ans=min(ans,dist[s1][j]+dist[j][i]+dist[i][t1]+dist[s2][j]+dist[i][t2]);
}
if(dist[s1][t1]>l1 || dist[s2][t2]>l2) //无解
cout<<-1<<endl;
else
cout<<m-ans<<endl;
return 0;
}