题目:
http://acm.hust.edu.cn/vjudge/contest/view.action?cid=94075#problem/G
题意:
给出一个矩阵,和范围【L,R】,求出是否存在a序列和b序列,使得 Cij * ai / bj 在L和R范围内。
思路:
可以得到式子 C * a/b >= L , C * a/b <= R
a / b >= L/C, a / b <= R/C
有一堆的不等式,可以想到差分约束,使用log 将除转化为减!!!
logb - loga <= -log(L/C) , loga - logb <= log(R/C)
判断负环,以及使用栈优化
AC.
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
#include <cmath>
using namespace std;
const double inf = 1e16;
const int maxn = 1e5+5;
const int maxm = 1e6+5;
int n, m;
int tot, head[maxn];
struct Edge{
int to, next;
double w;
}edge[maxm];
void init()
{
tot = 0;
for(int i = 0; i <= n+m; ++i) head[i] = -1;
}
void addedge(int u, int v, double w)
{
edge[tot].to = v;
edge[tot].w = w;
edge[tot].next = head[u];
head[u] = tot++;
}
int vis[maxn], ind[maxn];
double dis[maxn];
int Q[maxn];
bool spfa(int s)
{
int N = m+n;
int top = 0;
for(int i = 0; i <= N; ++i) {
vis[i] = ind[i] = 0;
dis[i] = inf;
}
//queue<int> que;
vis[s] = 1;
dis[s] = 0;
ind[s] = 1;
Q[top++] = s;
//que.push(s);
//int tmp = sqrt(N)+1;
while(top != 0) {
int u = Q[--top];
vis[u] = 0;
for(int i = head[u]; ~i; i = edge[i].next) {
int v = edge[i].to;
double w = edge[i].w;
if(dis[v] > dis[u] + w) {
dis[v] = dis[u] + w;
if(!vis[v]) {
vis[v] = 1;
Q[top++] = v;
if(++ind[v] > N) return false;
}
}
}
}
return true;
}
int main()
{
//freopen("in", "r", stdin);
double L, R;
while(~scanf("%d%d%lf%lf", &n, &m, &L, &R)) {
init();
for(int i = 1; i <= n; ++i) {
for(int j = 1; j <= m; ++j) {
double c;
scanf("%lf", &c);
addedge(j+n, i, log(R/c));
addedge(i, j+n, -log(L/c));
}
}
if(spfa(1)) {
printf("YES\n");
}
else printf("NO\n");
}
return 0;
}