POJ2749 Building road

传送门

这道题真是2-SAT好题啊!!卡了我两个点才做完……垃圾POJ还不告诉我哪错了……

首先我们先花一段时间把题看懂……(其实是翻译一下),之后我们发现因为每个谷仓只能向一个中转点连边,所以他就是一个布尔变量的两个取值。然后对于每个限制条件,其实就是^嘛!我们把他转换为合取范式之后建一下图。不过怎么计算最大距离最小值呢?看到这一幕想起二分答案……然后,然后就不会了……

我们再想一下,其实2-SAT里面,每个给定的限制特别要命,因为如果要没有限制随便瞎取都能合法,然后我们要限制一个最大距离……那我们不妨把连接之后距离大于当前值的两个谷仓加一个限制,使两者不能连边,这样我们再跑一遍2-SAT判断一下当前是否合法,然后改变二分的值就可以。

具体怎么加距离的限制,如果两个点通过某种连接方式之后不合法,我们就把其中一个向另一个的否定连边(一个点连接s1,s2),比如说第一个点连向s1,第二个点连向s2,如果这样是不合法的情况的话,那么我们强制性让第一个点连s2,第二个点连s1,这样建边就可以啦。

然而说着容易做着难……代码贼拉难写+忘记判断-1+不知道怎么建边……卡了两个小时。

Source Code
Problem: 2749        User: ifvisit
Memory: 6176K        Time: 1657MS
Language: C++        Result: Accepted

    Source Code

    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #include<iostream>
    #include<cmath>
    #include<set>
    #include<queue>
    #define rep(i,a,n) for(int i = a;i <= n;i++)
    #define per(i,n,a) for(int i = n;i >= a;i--)
    #define fill(x,y) memset(x,y,sizeof(x));
    #define enter putchar('
')

    using namespace std;
    typedef long long ll;
    const int M = 10005;
    const int N = 500005;
    const int INF = 1000000009;

    int read()
    {
        int ans = 0,op = 1;
        char ch = getchar();
        while(ch < '0' || ch > '9')
        {
        if(ch == '-') op = -1;
        ch = getchar();
        }
        while(ch >= '0' && ch <= '9')
        {
        ans *= 10;
        ans += ch - '0';
        ch = getchar();
        }
        return ans * op;
    }

    struct edge
    {
        int next,to,from;
    }e[N];

    struct node
    {
        int x,y;
    }q[M];

    struct relation
    {
        int a,b;
    }ha[M],li[M];

    int n,m,g,head[M],ecnt,dfn[M],low[M],stack[M],top,scc[M],a,b,c,d,dis1[M],dis2[M],len,idx,cnt;
    int minn = 100000000,maxn,ans;
    int s1 = 2000,s2 = 2001;
    bool vis[M];

    void add(int x,int y)
    {
        e[++ecnt].to = y;
        e[ecnt].from = x;
        e[ecnt].next = head[x];
        head[x] = ecnt;
    }
    int rev(int x)
    {
        return x > n ? x - n : x + n;
    }

    int mht(int kx,int ky)
    {
        return abs(q[kx].x - q[ky].x) + abs(q[kx].y - q[ky].y);
    }

    void clear()
    {
        memset(e,0,sizeof(e));
        memset(head,0,sizeof(head));
        memset(dfn,0,sizeof(dfn));
        memset(low,0,sizeof(low));
        memset(scc,0,sizeof(scc));
        ecnt = idx = cnt = 0;
    }

    void build(int x)
    {
        rep(i,1,m)
        {
        int r1 = ha[i].a,r2 = ha[i].b;
        add(r1,r2+n),add(r1+n,r2),add(r2,r1+n),add(r2+n,r1);
        }
        rep(i,1,g)
        {
        int r1 = li[i].a,r2 = li[i].b;
        add(r1,r2),add(r2,r1),add(r1+n,r2+n),add(r2+n,r1+n);
        }
        rep(i,1,n)
        {
        rep(j,i+1,n)
        {
            int l1 = dis1[i],l2 = dis2[i],r1 = dis1[j],r2 = dis2[j];
            if(l1 + r1 > x) add(i,j+n),add(j,i+n);
            if(l2 + r2 > x) add(i+n,j),add(j+n,i);
            if(l1 + r2 + len > x) add(i,j),add(j+n,i+n);
            if(l2 + r1 + len > x) add(i+n,j+n),add(j,i);
        }
        }
    }

    void tarjan(int x)
    {
        dfn[x] = low[x] = ++idx;
        stack[++top] = x,vis[x] = 1;
        for(int i = head[x];i;i = e[i].next)
        {
        if(!dfn[e[i].to]) tarjan(e[i].to),low[x] = min(low[x],low[e[i].to]);
        else if(vis[e[i].to]) low[x] = min(low[x],dfn[e[i].to]);
        }
        if(low[x] == dfn[x])
        {
        int p;
        cnt++;
        while((p = stack[top--]))
        {
            scc[p] = cnt,vis[p] = 0;
            if(p == x) break;
        }
        }
    }

    void solve()
    {
        int l = 0,r = 8000000;
        while(l < r)
        {
        bool flag = 0;
        int mid = (l+r) >> 1;
        clear(),build(mid);
        rep(i,1,n<<1) if(!dfn[i]) tarjan(i);
        rep(i,1,n)
        {
            if(scc[i] == scc[i+n])
            {
            flag = 1;
            break;
            }
        }
        if(flag) l = mid + 1;
        else r = mid;
        }
        if(l == 0 || l == 8000000) printf("-1
");
        else printf("%d
",l);
    }

    int main()
    {
        n = read(),m = read(),g = read();
        q[s1].x = read(),q[s1].y = read(),q[s2].x = read(),q[s2].y = read();
        len = abs(q[s2].y-q[s1].y) + abs(q[s2].x-q[s1].x);
        rep(i,1,n)
        {
        q[i].x = read(),q[i].y = read();
        dis1[i] = mht(i,s1),dis2[i] = mht(i,s2);
        }
        rep(i,1,m) ha[i].a = read(),ha[i].b = read();
        rep(i,1,g) li[i].a = read(),li[i].b = read();
        solve();
        return 0;
    }
原文地址:https://www.cnblogs.com/captain1/p/9761095.html