Codeforces 544D Destroying Roads【思维枚举+最短路】好题~好题!
2017-06-14 14:52
507 查看
D. Destroying Roads
time limit per test
2 seconds
memory limit per test
256 megabytes
input
standard input
output
standard output
In some country there are exactly n cities and
m bidirectional roads connecting the cities. Cities are numbered with integers from
1 to n. If cities
a and b are connected by a road, then in an hour you can go along this road either from city
a to city b, or from city
b to city a. The road network is such that from any city you can get to any other one by moving along the roads.
You want to destroy the largest possible number of roads in the country so that the remaining roads would allow you to get from city
s1 to city
t1 in at most
l1 hours and get from city
s2 to city
t2 in at most
l2 hours.
Determine what maximum number of roads you need to destroy in order to meet the condition of your plan. If it is impossible to reach the desired result, print -1.
Input
The first line contains two integers n,
m (1 ≤ n ≤ 3000,
![](http://codeforces.com/predownloaded/fb/9d/fb9d0bc73ad4b47281ded5285a73b7e25f6c534b.png)
) — the number of cities and roads in the country, respectively.
Next m lines contain the descriptions of the roads as pairs of integers
ai,
bi (1 ≤ ai, bi ≤ n,
ai ≠ bi). It is guaranteed that the roads that are given in the description can transport you from any city to any other one. It
is guaranteed that each pair of cities has at most one road between them.
The last two lines contains three integers each, s1,
t1,
l1 and s2,
t2,
l2, respectively (1 ≤ si, ti ≤ n,
0 ≤ li ≤ n).
Output
Print a single number — the answer to the problem. If the it is impossible to meet the conditions, print -1.
Examples
Input
Output
Input
Output
Input
Output
题目大意:
一个N个点,M条无向边的图。
让你确定最多可以去掉多少条边,使得从s1到t1的最短距离小于等于l1,并且使得从s2到t2的最短距离小于等于l2.
思路:
很显然,我们用的边越少,可以去掉的边就越多,问我们最多可以去掉多少条边,其实也就是再问我们最少用多少条边。
如果两条路没有相交重叠的部分,那么我们的最初答案肯定就是m-dist[s1][t1]-dist[s2][t2];
那么我们如何进行优化呢?使得使用的边尽可能的少呢?
答案很简单,我们希望两条路有重叠的部分。
又不难想到,对于两条路的重叠部分,其没有必要具有大于1段(交汇了之后如果再散开了就没有必要再汇在一起了,因为如果还有必要汇在一起的话就没有必要散开)。
再观察到数据范围N不是很大,所以我们可以O(n^2)来枚举重叠部分的起点和终点。
那么我们需要知道两点之间最短路,又因为每条边的长度都是1.那么其实SPFA是一个更好的选择(其实就变成了Bfs,O(n^2+m));
那么整理一下思路:
①我们SPFA预处理出两点间最短路。
②然后我们O(n^2)枚举重叠部分的起点和终点。
③然后判断两条路经过重叠部分是否都小于其各自的限制(l1,l2);
④维护答案。
这里注意一点:可能会存在重叠路径相反走向的情况,也就是说对于枚举出来的重叠部分两点u,v,对于两条路来讲,可能有一条从u-->v,另一条从v--->u.
所以枚举的时候再颠倒几次都判断一下即可。
Ac代码:
#include<stdio.h>
#include<string.h>
#include<vector>
#include<queue>
using namespace std;
vector<int >mp[3500];
int dist[3500][3500];
int vis[3500];
int n,m;
void SPFA(int ss,int d)
{
for(int i=1;i<=n;i++)dist[d][i]=0x3f3f3f3f;
dist[d][ss]=0;
memset(vis,0,sizeof(vis));
queue<int >s;
s.push(ss);
while(!s.empty())
{
int u=s.front();
vis[u]=0;
s.pop();
for(int i=0;i<mp[u].size();i++)
{
int v=mp[u][i];
if(dist[d][v]>dist[d][u]+1)
{
dist[d][v]=dist[d][u]+1;
if(vis[v]==0)
{
vis[v]=1;
s.push(v);
}
}
}
}
}
int main()
{
while(~scanf("%d%d",&n,&m))
{
for(int i=1;i<=n;i++)mp[i].clear();
for(int i=0;i<m;i++)
{
int x,y;
scanf("%d%d",&x,&y);
mp[x].push_back(y);
mp[y].push_back(x);
}
int s,t,len;
int ss,tt,lenn;
scanf("%d%d%d%d%d%d",&s,&t,&len,&ss,&tt,&lenn);
for(int i=1;i<=n;i++)
{
SPFA(i,i);
}
if(dist[s][t]>len||dist[ss][tt]>lenn)
{
printf("-1\n");
}
else
{
int output=m-dist[s][t]-dist[ss][tt];
if(output<0)output=0;
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
{
if(dist[s][i]+dist[i][j]+dist[j][t]<=len)
{
if(dist[ss][i]+dist[i][j]+dist[j][tt]<=lenn)
{
output=max(output,m-dist[i][j]-dist[s][i]-dist[ss][i]-dist[j][t]-dist[j][tt]);
}
}
if(dist[s][j]+dist[j][i]+dist[i][t]<=len)
{
if(dist[ss][i]+dist[i][j]+dist[j][tt]<=lenn)
{
output=max(output,m-dist[i][j]-dist[s][j]-dist[ss][i]-dist[i][t]-dist[j][tt]);
}
}
if(dist[s][i]+dist[i][j]+dist[j][t]<=len)
{
if(dist[ss][j]+dist[j][i]+dist[i][tt]<=lenn)
{
output=max(output,m-dist[i][j]-dist[s][i]-dist[ss][j]-dist[j][t]-dist[i][tt]);
}
}
if(dist[s][j]+dist[j][i]+dist[i][t]<=len)
{
if(dist[ss][j]+dist[j][i]+dist[i][tt]<=lenn)
{
output=max(output,m-dist[j][i]-dist[s][j]-dist[ss][j]-dist[i][t]-dist[i][tt]);
}
}
}
}
printf("%d\n",output);
}
}
}
time limit per test
2 seconds
memory limit per test
256 megabytes
input
standard input
output
standard output
In some country there are exactly n cities and
m bidirectional roads connecting the cities. Cities are numbered with integers from
1 to n. If cities
a and b are connected by a road, then in an hour you can go along this road either from city
a to city b, or from city
b to city a. The road network is such that from any city you can get to any other one by moving along the roads.
You want to destroy the largest possible number of roads in the country so that the remaining roads would allow you to get from city
s1 to city
t1 in at most
l1 hours and get from city
s2 to city
t2 in at most
l2 hours.
Determine what maximum number of roads you need to destroy in order to meet the condition of your plan. If it is impossible to reach the desired result, print -1.
Input
The first line contains two integers n,
m (1 ≤ n ≤ 3000,
![](http://codeforces.com/predownloaded/fb/9d/fb9d0bc73ad4b47281ded5285a73b7e25f6c534b.png)
) — the number of cities and roads in the country, respectively.
Next m lines contain the descriptions of the roads as pairs of integers
ai,
bi (1 ≤ ai, bi ≤ n,
ai ≠ bi). It is guaranteed that the roads that are given in the description can transport you from any city to any other one. It
is guaranteed that each pair of cities has at most one road between them.
The last two lines contains three integers each, s1,
t1,
l1 and s2,
t2,
l2, respectively (1 ≤ si, ti ≤ n,
0 ≤ li ≤ n).
Output
Print a single number — the answer to the problem. If the it is impossible to meet the conditions, print -1.
Examples
Input
5 4 1 2 2 3 3 4 4 5 1 3 2 3 5 2
Output
0
Input
5 4 1 2 2 3 3 4 4 5 1 3 2 2 4 2
Output
1
Input
5 4
1 2
2 3
3 4
4 5
1 3 2
3 5 1
Output
-1
题目大意:
一个N个点,M条无向边的图。
让你确定最多可以去掉多少条边,使得从s1到t1的最短距离小于等于l1,并且使得从s2到t2的最短距离小于等于l2.
思路:
很显然,我们用的边越少,可以去掉的边就越多,问我们最多可以去掉多少条边,其实也就是再问我们最少用多少条边。
如果两条路没有相交重叠的部分,那么我们的最初答案肯定就是m-dist[s1][t1]-dist[s2][t2];
那么我们如何进行优化呢?使得使用的边尽可能的少呢?
答案很简单,我们希望两条路有重叠的部分。
又不难想到,对于两条路的重叠部分,其没有必要具有大于1段(交汇了之后如果再散开了就没有必要再汇在一起了,因为如果还有必要汇在一起的话就没有必要散开)。
再观察到数据范围N不是很大,所以我们可以O(n^2)来枚举重叠部分的起点和终点。
那么我们需要知道两点之间最短路,又因为每条边的长度都是1.那么其实SPFA是一个更好的选择(其实就变成了Bfs,O(n^2+m));
那么整理一下思路:
①我们SPFA预处理出两点间最短路。
②然后我们O(n^2)枚举重叠部分的起点和终点。
③然后判断两条路经过重叠部分是否都小于其各自的限制(l1,l2);
④维护答案。
这里注意一点:可能会存在重叠路径相反走向的情况,也就是说对于枚举出来的重叠部分两点u,v,对于两条路来讲,可能有一条从u-->v,另一条从v--->u.
所以枚举的时候再颠倒几次都判断一下即可。
Ac代码:
#include<stdio.h>
#include<string.h>
#include<vector>
#include<queue>
using namespace std;
vector<int >mp[3500];
int dist[3500][3500];
int vis[3500];
int n,m;
void SPFA(int ss,int d)
{
for(int i=1;i<=n;i++)dist[d][i]=0x3f3f3f3f;
dist[d][ss]=0;
memset(vis,0,sizeof(vis));
queue<int >s;
s.push(ss);
while(!s.empty())
{
int u=s.front();
vis[u]=0;
s.pop();
for(int i=0;i<mp[u].size();i++)
{
int v=mp[u][i];
if(dist[d][v]>dist[d][u]+1)
{
dist[d][v]=dist[d][u]+1;
if(vis[v]==0)
{
vis[v]=1;
s.push(v);
}
}
}
}
}
int main()
{
while(~scanf("%d%d",&n,&m))
{
for(int i=1;i<=n;i++)mp[i].clear();
for(int i=0;i<m;i++)
{
int x,y;
scanf("%d%d",&x,&y);
mp[x].push_back(y);
mp[y].push_back(x);
}
int s,t,len;
int ss,tt,lenn;
scanf("%d%d%d%d%d%d",&s,&t,&len,&ss,&tt,&lenn);
for(int i=1;i<=n;i++)
{
SPFA(i,i);
}
if(dist[s][t]>len||dist[ss][tt]>lenn)
{
printf("-1\n");
}
else
{
int output=m-dist[s][t]-dist[ss][tt];
if(output<0)output=0;
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
{
if(dist[s][i]+dist[i][j]+dist[j][t]<=len)
{
if(dist[ss][i]+dist[i][j]+dist[j][tt]<=lenn)
{
output=max(output,m-dist[i][j]-dist[s][i]-dist[ss][i]-dist[j][t]-dist[j][tt]);
}
}
if(dist[s][j]+dist[j][i]+dist[i][t]<=len)
{
if(dist[ss][i]+dist[i][j]+dist[j][tt]<=lenn)
{
output=max(output,m-dist[i][j]-dist[s][j]-dist[ss][i]-dist[i][t]-dist[j][tt]);
}
}
if(dist[s][i]+dist[i][j]+dist[j][t]<=len)
{
if(dist[ss][j]+dist[j][i]+dist[i][tt]<=lenn)
{
output=max(output,m-dist[i][j]-dist[s][i]-dist[ss][j]-dist[j][t]-dist[i][tt]);
}
}
if(dist[s][j]+dist[j][i]+dist[i][t]<=len)
{
if(dist[ss][j]+dist[j][i]+dist[i][tt]<=lenn)
{
output=max(output,m-dist[j][i]-dist[s][j]-dist[ss][j]-dist[i][t]-dist[i][tt]);
}
}
}
}
printf("%d\n",output);
}
}
}
相关文章推荐
- Codeforces 593B Anton and Lines 【思维】【枚举】【排序】
- Codeforces 485D Maximum Value【思维+技巧枚举】
- Codeforces 466B Wonder Room【思维+暴力枚举】直觉题
- CodeForces - 786B Legacy(线段树 +最短路+思维好题)
- 51nod 1444 破坏道路【思维+最短路+枚举】这种题好套路啊
- Codeforces 426D Sereja and Table【思维+暴力枚举】好题!
- Codeforces 846C Four Segments【思维+预处理+前缀和枚举】
- Codeforces--333C--The Two Routes(最短路弗洛伊德)(思维)
- Codeforces 716D Complete The Graph【思维+最短路】
- Codeforces 599D Spongebob and Squares【思维枚举+数学方程】
- Codeforces 144 D Missile Silos【最短路SPFA+枚举】
- Codeforces Round #378 (Div. 2) && codeforces 733D(思维枚举)
- Codeforces 769D k-Interesting Pairs Of Integers【思维+预处理+暴力枚举】
- Codeforces 672C Recycling Bottles【极限思维+贪心枚举】
- Codeforces 551B ZgukistringZ【思维+枚举】
- Codeforces 667D World Tour【最短路+思维】好题!
- Codeforces 602C The Two Routes【最短路+思维】
- UVALive-7220 Dungeon Trap【最短路Bfs+思维枚举】好题~
- HDU 6166 Senior Pan (思维枚举+最短路 求最近点对)
- CodeForces 543B Destroying Roads(最短路 + 枚举)