题意:给你一个N*M的矩阵C,再给你一个L,U,问是否存在 a1,a2.....an和b1,b2.....bn ,使得 L<=Cij∗ai/bj<=R
题解:看到不等式就想起来差分约束,但是差分约束只能解决
A−B>=C
的问题,乘除怎么转化为加减?取对数。
取对数:
L/(Cij)<=(ai/bj)<=R/(Cij)
log(L)−log(Cij)<=log(ai)−log(bj)<=log(R)−LOG(Cij)
L,Cij,R
都为已知,
ai,bj
为未知,转换成差分约束的情况判断是否存在负环就好了。
注意
L,R
均为浮点数。
优化:判负环应该判一个点入队次数大于
n+m−−−−−√
,不然会超时。
#include<bits/stdc++.h>
using namespace std;
#define inf 0x7fffffff
const int maxn = 405;
int head[maxn * maxn], n, m,cnt[maxn * maxn],nm,k;
double low[maxn * maxn],l,u;
bool used[maxn * maxn];
struct Edge
{
int to, next;
double w;
} edge[maxn * maxn * 10];
int SPFA(int start,int n)
{
nm = sqrt(n*1.0);
for(int i = 0; i <= n; ++i)
{
low[i] = inf;
used[i] = 0;
cnt[i] = 0;
}
queue<int> a;
used[start] = 1;
low[start] = 0;
a.push(start);
while (!a.empty())
{
int top = a.front();
a.pop();
used[top]=0;
for (int k = head[top]; k != -1; k = edge[k].next)
{
if (low[edge[k].to] > low[top] + edge[k].w)
{
low[edge[k].to] = low[top] + edge[k].w;
if (!used[edge[k].to])
{
if(++cnt[edge[k].to]>nm){return 0;}
used[edge[k].to] = 1;
a.push(edge[k].to);
}
}
}
}
return 1;
}
void add(int a,int b,double w)
{
edge[k].to = b;
edge[k].w = w;
edge[k].next = head[a];
head[a] = k++;
}
int main()
{
while (~scanf("%d %d %lf %lf",&n,&m,&l,&u))
{
double L = log(l),U = log(u);
k = 0;
memset(head,-1,sizeof head);
for (int i = 0 ; i < n; i++)
{
for (int j = 0; j < m; j++)
{
double c;
scanf("%lf",&c);
add(j + n,i,U - log(c));
add(i,j + n,-(L - log(c)));
}
}
if(SPFA(0,n+m))
{
printf("YES\n");
}
else printf("NO\n");
}
}