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

题目大意:给出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;
}

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

时间: 2024-10-10 20:37:22

UVALive - 5906 Smoking gun(差分约束系统+拓扑排序)的相关文章

【差分约束系统】【强连通分量缩点】【拓扑排序】【DAG最短路】CDOJ1638 红藕香残玉簟秋,轻解罗裳,独上兰舟。

题意: 给定n个点(点权未知)和m条信息:u的权值>=v的权值+w 求点权的极小解和极大解(无解则输出-1) 极小解即每个点的点权可能的最小值 极大解即每个点的点权可能的最大值 题解: 差分约束系统 对于val[u]>=val[v]+w 要得到极小解,v是没有受限制的,其最小值为0 而u受到v的限制,显然,val[u]的最小值就是val[v]+w 在多条件限制下,我们用v连向u边权为w的边表示每个限制条件val[u]>=val[v]+w 那么如果得到的是拓扑图,则按拓扑序求到每个点的最长

UVALive 6467 Strahler Order 拓扑排序

这题是今天下午BNU SUMMER TRAINING的C题 是队友给的解题思路,用拓扑排序然后就可以了 最后是3A 其中两次RE竟然是因为: scanf("%d",mm); ORZ 以后能用CIN还是CIN吧 QAQ 贴代码了: 1 #include <stdio.h> 2 #include <string.h> 3 #include <stdlib.h> 4 #include <math.h> 5 #include <iostre

UVALive 6264 Conservation --拓扑排序

题意:一个展览有n个步骤,告诉你每一步在那个场馆举行,总共2个场馆,跨越场馆需要1单位时间,先给你一些约束关系,比如步骤a要在b前执行,问最少的转移时间是多少. 解法:根据这些约束关系可以建立有向边,可以看出是拓扑排序问题,问题是怎样拓扑排序. 进行两次拓扑排序,分别建立两个集合,一个放场馆1举行的步骤,一个放场馆2的,然后第一次从场馆1开始进行拓扑排序,每次一个场馆取完后看另一个场馆是否有步骤要执行,有则执行,然后将度数变为0的压入队列,如此往复.第二次从场馆2开始进行.得出的最小值为答案.

Guess UVALive - 4255 (拓扑排序)

Guess UVALive - 4255 题意: 拓扑排序 1 #include <bits/stdc++.h> 2 using namespace std; 3 4 const int maxn=12; 5 int p[maxn][maxn],b[maxn]; 6 int in[maxn]; 7 int n; 8 9 void top_sort(){ 10 queue<int> q; 11 for(int i=0;i<=n;i++) if(in[i]==0) q.push(

D - Guess UVALive - 4255 拓扑排序

Given a sequence of integers, a1, a2, . . . , an, we define its sign matrix S such that, for 1 ≤ i ≤ j ≤ n, Sij = " + " if ai + . . . + aj > 0; Sij = " ? " if ai + . . . + aj < 0; and Sij = "0" otherwise. For example, i

UVALive - 4255 - Guess (拓扑排序)

Guess 题目传送:Guess 白书例题 注意拓扑排序时,,入度同一时候为0的前缀和须要赋值为同一个数(这个数能够随机取.由于前缀和是累加的,每个a的数值都仅仅和前缀和之差有关).,由于此时能够看成他们的前缀和是相等的,不存在大小关系,,而存在大小关系的都连了一条有向边. .假设此时不赋值为同一个数,,可能对于符号0不是正解.,从而产生错误的结果.. AC代码: #include <map> #include <set> #include <list> #includ

uvalive 6393(uva 1572) Self-Assembly 拓扑排序

题意: 给出一些正方形,这些正方形的每一条边都有一个标号,这些标号有两种形式:1.一个大写字母+一个加减号(如:A+, B-, A-......), 2.两个0(如:00):这些正方形可以随意翻转和旋转,当两个正方形通过旋转或翻转,使得他们的公共边为相同大写字母并且符号相反时,他们就可以彼此结合拼在一起,现在给出n中正方形,每种正方形有无限多种,问这些正方形能否拼成一个无限大的结构. 题解: 容易想到,要使这些正方形形成无限大地结构,那么这些正方形通过拼接后一定能循环(即通过不断地拼接出现了和以

【每日算法】图算法(遍历&amp;MST&amp;最短路径&amp;拓扑排序)

图有邻接矩阵和邻接表两种存储方法,邻接矩阵很简单,这里不讨论,下面我们先看看常用的邻接表表示方法. 邻接表常用表示方法 指针表示法 指针表示法一共需要两个结构体: struct ArcNode //定义边表结点 { int adjvex: //邻接点域 ArcNode* next; }; struct VertexNode //定义顶点表结点 { int vertex; ArcNode* firstedge; }; 每个节点对应一个VertexNode,其firstedge指向边表(与当前节点邻

HDU 3342 -- Legal or Not【裸拓扑排序 &amp;&amp;水题】

Legal or Not Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 5906    Accepted Submission(s): 2734 Problem Description ACM-DIY is a large QQ group where many excellent acmers get together. It is