题意: 给出一个矩阵, 问是否存在两个序列
a1,a2...an
和
b1,b2...bm
使得
ai×ci,j/bj∈[L,U]
.
整理一下条件就是要判断是否存在两个数列使得
f(x)={ai×ci,j≤U×bjL×bj≤ai×ci,j
然后用log去乘号:
f(x)={log(ai)−log(bj)≤log(U/ci,j)log(bj)−log(ai)≤log(ci,j/L)
然后判断负环就好了. 如果判定条件是入队次数大于n会超时, 用另一种判断:
入队次数≥n+m−−−−−√
.
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <vector>
#include <queue>
using namespace std;
#define INF 1e14
#define eps 1e-8
#define maxn 10005
#define maxm 1500000
int n, m;
double l, u;
double c[411][411];
struct node {
int v, next;
double w;
}edge[maxm];
int head[maxn], cnt;
double dcmp (double x) {
if (fabs (x) <= eps) return 0;
else return x < 0 ? -1 : 1;
}
void init () {
memset (head, -1, sizeof head);
cnt = 0;
}
void add_edge (int u, int v, double w) {
edge[cnt].v = v, edge[cnt].next = head[u], edge[cnt].w = w, head[u] = cnt++;
}
bool vis[maxn];
int top, num[maxn];
double d[maxn];
bool spfa (int start, int n, int m) {
memset (vis, 0, sizeof vis);
for (int i = 1; i <= n; i++) {
d[i] = INF;
}
vis[start] = 1;
d[start] = 0;
queue <int> q;
while (!q.empty ()) q.pop ();
q.push (start);
memset (num, 0, sizeof num);
num[start] = 1;
while (!q.empty ()) {
int u = q.front (); q.pop ();
vis[u] = 0;
for (int i = head[u]; i != -1; i = edge[i].next) {
int v = edge[i].v;
if (d[v]>d[u]+edge[i].w) {
d[v] = d[u]+edge[i].w;
if (!vis[v]) {
vis[v] = 1;
q.push (v);
if (++num[v] > (int)sqrt ((1.0*n+m)))
return 0;
}
}
}
}
return 1;
}
int main () {
while (scanf ("%d%d", &n, &m) == 2) {
scanf ("%lf%lf", &l, &u);
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
scanf ("%lf", &c[i][j]);
}
}
init ();
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
add_edge (i, n+j, log10 (u/c[i][j]));
add_edge (n+j, i, log10 (c[i][j]/l));
}
}
if (spfa (0, n+m, 2*(n+m)))
printf ("YES\n");
else
printf ("NO\n");
}
return 0;
}