您的位置:首页 > 其它

UVALive - 5906 Smoking gun(差分约束系统+拓扑排序)

2015-08-21 00:04 246 查看
题目大意:给出N个人的坐标和M个听到枪声的顺序,问是否有一个开枪顺序能满足着M个条件,是一个还是多少?

解题思路:典型的差分约束系统,设第i个人开枪时间为ti

假设a先听到b的枪声,再听到c的枪声

那么就要满足一个条件

tb + dis(a,b) <= tc + dis(a,c)(这里本来都要除以音速的,但此处可以省略)

由这个不等式构造边,具体构造就不说了,了解差分约束系统的都会构造,如果不会,证明你还不太了解

接着判断,如果有环,表明条件不可能全部成立

在条件成立的情况下,拓扑一下,如果拓扑失败,表明有多个开枪顺序了,如果成功,就只有一个了

[code]#include <cstdio>
#include <cstring>
#include <iostream>
#include <map>
#include <vector>
#include <cmath>
#include <queue>
#include <set>

using namespace std;

#define N 110
#define M 1010

struct Node{
    string s;
    int x, y;
}node
;

struct Edge{
    int u, v, next;
    double c;
}E[M];

map<string,int> name;
vector<int> vec
;
set<int> Tuopu;
int n, m, tot;
int head
;
char str1
, str2
, str3
;

void AddEdge(int u, int v, double c) {
    E[tot].u = u; E[tot].v = v; E[tot].c = c; E[tot].next = head[u]; head[u] = tot++;
}

double distance(int i, int j) {
    int x = node[i].x - node[j].x;
    int y = node[i].y - node[j].y;
    return sqrt(1.0 * x * x + 1.0 * y * y);
}

void init() {
    scanf("%d%d", &n, &m);
    name.clear();
    Tuopu.clear();

    string s1, s2, s3;
    int x, y;
    for (int i = 1; i <= n; i++) {
        cin >> node[i].s >> node[i].x >> node[i].y;
        name[node[i].s] = i; 
        vec[i].clear();
    }

    memset(head, -1, sizeof(head));
    tot = 0;
    // u + dist1 <= v + dist2
    for (int i = 0; i < m; i++) {
        scanf("%s heard %s firing before %s", str1, str2, str3);
        s1 = str1; s2 = str2; s3 = str3;
        double dist1 = distance(name[s2], name[s1]);
        double dist2 = distance(name[s3], name[s1]);
        int u = name[s2];
        int v = name[s3];
        Tuopu.insert(u);
        Tuopu.insert(v);
        AddEdge(v, u, dist2 - dist1);
    }
}

#define INF 0x3f3f3f3f
#define esp 1e-8
double d
;
bool vis
;
int in
, cnt
;

bool spfa(int s) {
    memset(cnt, 0, sizeof(cnt));
    memset(vis, 0, sizeof(vis));
    for (int i = 1; i <= n; i++) 
        d[i] = INF;
    queue<int> Q;
    d[s] = 0;
    Q.push(s);

    while (!Q.empty()) {
        int u = Q.front();
        Q.pop();

        for (int i = head[u]; ~i; i = E[i].next) {
            int v = E[i].v;
            if (d[v] > d[u] + esp + E[i].c) {
                d[v] = d[u] + E[i].c;
                if (!vis[v]) {
                    vis[v] = true;
                    Q.push(v);
                    if (++cnt[v] >= n) return false;
                }
            }
        }
        vis[u] = false;
    }

    for (int i = 1; i <= n; i++) 
        if (d[i] < -esp) {
            vec[i].push_back(s);
            in[s]++;
            Tuopu.erase(s);
        }
    return true;
}

void solve() {
    memset(in, 0, sizeof(in));
    for (int i = 1; i <= n; i++) 
        if (!spfa(i)) {
            printf("IMPOSSIBLE\n");
            return ;
        }
    queue<int> ans;
    while (Tuopu.size()) {
        if (Tuopu.size() > 1) {
            printf("UNKNOWN\n");
            return ;
        }
        int t = *Tuopu.begin();
        ans.push(t);
        Tuopu.erase(t);
        for (int i = 0; i < vec[t].size(); i++) {
            --in[vec[t][i]];
            if (in[vec[t][i]] == 0)
                Tuopu.insert(vec[t][i]);
        }
    }

    cout << node[ans.front()].s;
    ans.pop();  
    while (!ans.empty())  {
        cout << " " << node[ans.front()].s;
        ans.pop();
    }
    printf("\n");
}

int main() {
    int test;
    scanf("%d", &test);
    while (test--) {
        init();
        solve();
    }
    return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: