Codeforces 101652T DFS 离散化

题目:传送门

题意:

n个房间,m个门,k个人编号[1,k],门上有区间[l,r],只有人的编号在区间内才能通过门,门是单向门,也就是说只能从一个房间到另一个房间,而不能从另一个房间到本房间,告诉你起点s房间和终点t房间,问:假设现在所有的人都在s房间,他们都想去t房间,最后一共多少个人能够到达t房间

题解:

题目很好理解,先建个图,然后DFS或者BFS。问题的关键是怎么搜索。
如果不离散化,我第一开始是这样想的:
1遍历到k,然后kDFS,看当前编号是否能从st。但是这样的复杂度是 O ( ( n + m ) k ) ,而k的上限是 10 9 ,复杂度太高了。想到这里我以为暴搜不行,要上带有上下界的区间网络流,因为我之前做过类似的题。POJ2396
后来一起比赛的队友(队友博客)想到可以离散化,把k降到 2 m ,想法非常巧妙,记录如下:
不难想到,第一种搜索是以点为单位的,很多点的搜索路径一定重复的,如何把这些重复的点找到?需要区间离散化,我们把所有的区间放入一个数组(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;
}

猜你喜欢

转载自blog.csdn.net/shadandeajian/article/details/81750852