码迷,mamicode.com
首页 > 编程语言 > 详细

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

时间:2015-08-21 00:08:14      阅读:294      评论:0      收藏:0      [点我收藏+]

标签:

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

解题思路:典型的差分约束系统,设第i个人开枪时间为ti
假设a先听到b的枪声,再听到c的枪声
那么就要满足一个条件
tb + dis(a,b) <= tc + dis(a,c)(这里本来都要除以音速的,但此处可以省略)
由这个不等式构造边,具体构造就不说了,了解差分约束系统的都会构造,如果不会,证明你还不太了解
接着判断,如果有环,表明条件不可能全部成立
在条件成立的情况下,拓扑一下,如果拓扑失败,表明有多个开枪顺序了,如果成功,就只有一个了

#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[N];

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

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

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[N];
bool vis[N];
int in[N], cnt[N];

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;
}

版权声明:本文为博主原创文章,未经博主允许不得转载。

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

标签:

原文地址:http://blog.csdn.net/l123012013048/article/details/47820099

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!