1. 程式人生 > 實用技巧 >HDU-6252 - Subway Chasing(差分約束/不等式組)

HDU-6252 - Subway Chasing(差分約束/不等式組)

HDU-6252 - Subway Chasing(差分約束/不等式組)

題目連結: HDU - 6252

題面:

題意:

雷格西桑和路易桑是好朋友,在同一家公司工作。他們總是一起乘地鐵去上班。他們的路線上有N個地鐵站,編號從1到N。1站是他們的家,N站是公司。
有一天,雷格西桑起床晚了。當他來到車站時,路易桑已經離開X分鐘了。雷格西桑非常著急,於是他開始和路易桑聊天,交流他們的位置。內容是雷格西桑在A站和B站之間,路易桑在C站和D站之間。
B等於A+ 1這意味著雷格西在A站和A+1之間, 或B等於A這意味著雷格西就是在車站A,反之亦然對於C和D同理.更重要的是,他們交流的時間不能早於雷格西桑的離開,也不能晚於路易桑的到來。
到達公司後,雷格西桑想知道相鄰地鐵站之間的間隔時間。請注意,每個站點的停止時間都被忽略。

思路:

\(t_i=d_{i+1}-d_i\)

考慮到兩人的每一句聊天都對應著一個關於\(t_i\)的不等式組。

對應關係為:

  • 若:\(a=b,c=d\)則:

    • 若:\(a=c\),則表明兩人位置相同,又\(x>0\),故答案為”IMPOSSIBLE“,
    • 否則:\(d_{i+1}=d_i+x\)
  • 若:\(a = b , c < d\) ,則:\(d_{c}-d_a<x\)

  • 若:\(a < b , c = d\),則:\(d_d-d_a>x\),如果\(b!=c\),則\(d_c-d_b<x\)

  • 若:\(a < b , c < d\)

    ,如果\(a!=c\),則\(d_d-d_a>x,d_c-d_b<x\)

    否則:\(d_b-d_a>x\).

然後 用差分約束模型建圖,用spfa演算法跑最長路,若有正環則輸出無解。否則可得到最小解。

程式碼:

#include <bits/stdc++.h>
using namespace std;
typedef pair<int, int> pii;
const int maxn = 3e3 + 10;
vector<pii> e[maxn];
int cnt[maxn];
bool inque[maxn];
int dis[maxn];
const int inf = 2e9 + 5;
#define fi first
#define se second

bool check(int n)
{
    for (int i = 1; i <= n; ++i) {
        cnt[i] = 0;
        dis[i] = -1;
        inque[i] = 0;
    }
    queue<int> q;
    q.push(0);
    cnt[0] = 1;
    int temp;
    dis[0] = 0;
    while (!q.empty()) {
        temp = q.front();
        q.pop();
        inque[temp] = 0;
        for (auto x : e[temp]) {
            if (dis[x.fi] < dis[temp] + x.se) {
                dis[x.fi] = dis[temp] + x.se;
                if (!inque[x.fi]) {
                    inque[x.fi] = 1;
                    q.push(x.fi);
                    cnt[x.fi]++;
                    if (cnt[x.fi] > n) {
                        return 0;
                    }
                }
            }
        }
    }
    return 1;
}


#define mp make_pair
int main()
{
    int t;
    scanf("%d", &t);
    for (int icase = 1; icase <= t; ++icase) {
        int n, m, x;
        scanf("%d %d %d", &n, &m, &x);
        bool flag = 0;
        for (int i = 1; i <= m; ++i) {
            int a, b, c, d;
            scanf("%d %d %d %d", &a, &b, &c, &d);
            if (a > c) {
                flag = 1;
            }
            if (a == b && c == d) {
                if (a == c) {
                    flag = 1;
                }
                e[b].push_back(mp(c, x));
                e[c].push_back(mp(b, -x));
            } else if (a == b && c < d) {
                e[c].push_back(mp(b, -(x - 1)));
                e[a].push_back(mp(d, x + 1));
            } else if (a < b && c == d) {
                e[c].push_back(mp(b, -(x - 1)));
                e[a].push_back(mp(d, x + 1));
            } else if (a < b && c < d && a != c) {
                e[a].push_back(mp(d, x + 1));
                e[c].push_back(mp(b, -(x - 1)));
            } else {
                e[a].push_back(mp(b, x + 1));
            }
        }
        int S = 0;
        for (int i = 1; i <= n; ++i) {
            e[S].push_back(mp(i, 0));
        }
        for (int i = 1; i < n; ++i) {
            e[i].push_back(mp(i + 1, 1));
        }
        printf("Case #%d: ", icase);
        if (!flag && check(n)) {
            for (int i = 2; i <= n; ++i) {
                printf("%d%c", dis[i] - dis[i - 1], i == n ? '\n' : ' ');
            }
        } else {
            printf("IMPOSSIBLE\n");
        }
        for (int i = 0; i <= n; ++i) {
            e[i].clear();
        }
    }
    return 0;
}