标签:
题目大意:给出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