题目:传送门
题意:
n个房间,m个门,k个人编号[1,k],门上有区间[l,r],只有人的编号在区间内才能通过门,门是单向门,也就是说只能从一个房间到另一个房间,而不能从另一个房间到本房间,告诉你起点s房间和终点t房间,问:假设现在所有的人都在s房间,他们都想去t房间,最后一共多少个人能够到达t房间。
题解:
题目很好理解,先建个图,然后DFS或者BFS。问题的关键是怎么搜索。
如果不离散化,我第一开始是这样想的:
从1遍历到k,然后k遍DFS,看当前编号是否能从s到t。但是这样的复杂度是
,而k的上限是
,复杂度太高了。想到这里我以为暴搜不行,要上带有上下界的区间网络流,因为我之前做过类似的题。POJ2396
后来一起比赛的队友(队友博客)想到可以离散化,把k降到
,想法非常巧妙,记录如下:
不难想到,第一种搜索是以点为单位的,很多点的搜索路径一定重复的,如何把这些重复的点找到?需要区间离散化,我们把所有的区间放入一个数组(vector a),然后排序,我们只需要DFS(i+1,a.size()),判断每一个区间的边界是不是可以到达,可以到达的话,ans+=a[i]-a[i-1]第一开始我认为这样会判重复,相交区间会加多次,想了一下,根本不会重复,因为已经把区间离散化了,每一小段都是唯一的。
AC代码:
#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
#include <vector>
#define debug(x) cout<<#x<<" = "<<x<<endl;
#define INF 0x3f3f3f3f
using namespace std;
const int maxv = 1010;
const int maxe = 5010;
bool vis[maxv];
int cnt, head[maxv];
struct Edge {
int to , next, l, r;
} edge[maxe];
void init() {
memset(head, -1, sizeof head);
}
void addedge(int from, int to, int l, int r) {
edge[cnt].to = to;
edge[cnt].l = l;
edge[cnt].r = r;
edge[cnt].next = head[from];
head[from] = cnt++;
}
void dfs(int u, int val) {
if (vis[u])
return ;
vis[u] = true;
for (int i = head[u]; i != -1; i = edge[i].next) {
if (edge[i].l <= val && val <= edge[i].r)
dfs(edge[i].to, val);
}
}
int main(void) {
init();
int n, m, k, from, to, l, r, s, t, ans = 0;
vector<int> a;//离散化区间
cin >> n >> m >> k >> s >> t;
for (int i = 0; i < m; i++) {
cin >> from >> to >> l >> r;
addedge(from, to, l, r);
a.push_back(l - 1);
a.push_back(r);
}
sort(a.begin(), a.end());
for (int i = 1; i < (int)a.size(); i++) {
if (a[i] - a[i - 1] == 0)
continue;
memset(vis, false , sizeof vis);
dfs(s, a[i]);
if (vis[t])
ans += a[i] - a[i - 1];
}
cout << ans << endl;
return 0;
}