CF 543B 图,最短路

题目链接:http://codeforces.com/problemset/problem/543/B


题意:总共有n个点(1<= n<=3000),m条边(m <= min(3000,n * (n - 1) / 2)),任意两点间只有一条边,边的长度都为1,一开始的时候所有点都能通过某些路径到达。要你求最多删除几条边,能使s1到t1的距离不超过l1,s2到t2的距离不超过l2,如果情况不存在,输出-1,否则输出最多删的边的条数。


思路:看到点的个数比较少,可以先把所有i到j的最短路算出来,并用邻接矩阵存起来,O(n^2)复杂度。接下来只要考虑两种情况:1.s1到t1和s2到t2的路径中没有重合的边,那么只要单独算两条路径的最短路即可。2.从两条路径的一个端点出发,路径中会出现先没有边重合,后来有边重合,最后又没有边重合的情况。对于第2种情况,只要枚举重合路径的两个端点,然后不断更新答案就可以了。

另外需要特别注意的是,两个路径可能是从s1,s2出发(t1,t2也一样。。。)或者是s1,t2出发(s2,t1也一样。。。),这是两种不同的情况要分开考虑,所以还要swap(s1,t1)才能AC。。。。


#include <bits/stdc++.h>
#define mem(a,b) memset(a,b,sizeof(a))
typedef long long ll;
using namespace std;
const int maxn = 3005;
int dis[maxn][maxn];
vector<int> vec[maxn];

int n,m;
void bfs(int x)
{
	queue<int> que;
	dis[x][x] = 0;
	que.push(x);
	while(!que.empty())
	{
		int temp = que.front();
		que.pop();
		for(int i = 0;i < vec[temp].size();i++)
		{
			int v = vec[temp][i];
			if(dis[x][v] == -1)
			{
				dis[x][v] = dis[x][temp] + 1;
				que.push(v);
			}
		}
	}
}
int s[2],t[2],l[2];

void show()
{
	for(int i = 1;i <= n;i++)
	{
		for(int j = 1;j <= n;j++)
			cout<<dis[i][j]<<" ";
		cout<<endl;
	}
}
int main()
{
	while(~scanf("%d%d",&n,&m))
	{
		mem(dis,-1);
		for(int i = 0;i <= n + 1;i++)vec[i].clear();
		for(int i = 0,a,b;i < m;i++)
		{
			scanf("%d%d",&a,&b);
			vec[a].push_back(b);
			vec[b].push_back(a);
		}
		for(int i = 1;i <= n;i++)
			bfs(i);
		scanf("%d%d%d%d%d%d",&s[0],&t[0],&l[0],&s[1],&t[1],&l[1]);
		int ans = 999999999;
		for(int oper = 0;oper < 2;oper++)
		{
			swap(s[1],t[1]);
			for(int i = 1;i <= n;i++)
				for(int j = 1;j <= n;j++)
				{
					int v[] = {dis[s[0]][i] + dis[i][j] + dis[j][t[0]],dis[s[1]][i] + dis[i][j] + dis[j][t[1]]};
					if(v[0] <= l[0] && v[1] <= l[1])
					{
						ans = min(ans,v[0] + v[1] - dis[i][j]);
					}
				}
		}
		if(dis[s[0]][t[0]] <= l[0] && dis[s[1]][t[1]] <= l[1])
			ans = min(ans,dis[s[0]][t[0]] + dis[s[1]][t[1]]);
		if(ans > m)
			ans = -1;
		else 
			ans = m - ans;
		printf("%d\n",ans);
	}
}


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值