cf-543-B.Destroying Roads-最短路+暴力

这里写图片描述

题意:

有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;
}

猜你喜欢

转载自blog.csdn.net/weixin_43093481/article/details/82467336