Description
- 给你一个M×N的矩阵,矩阵元素为不超过
1000
的正数,问是否存在n
个数的序列a1,a2,...,an,和m
个数b1,b2,...,bm,满足使第i
行的每个元素乘以ai,第j
列中的每个元素除以bj之后,这个矩阵中的每个元素都在L
和U
之间,L
表示元素的下界,U
表示元素的上界。
Input
- 存在多组数据
- 每组数据第一行有四个整数
N,M,L,U
(1<=N,M<=400,1<=L<=U<=10000
),接下来N
行,每行M
个整数,表示矩阵元素。
Output
- 如果存在输出
YES
,否则输出NO
。
Sample Input
3 3 1 6
2 3 4
8 2 6
5 2 9
Sample Output
YES
思路
这道题和差分约束有什么关系呢?
用 mp 表示矩阵
根据题意有: L <= mp[i][j]*a[i]/b[j] <= R
移项可得: L/mp[i][j] <= a[i]/b[j] <= R/mp[i][j]
因为我们不用求出具体的值,只需判断是否满足条件,对两边取对数可以把除法变成减法
两边取对数: log(L/mp[i][j]) <= log(a[i]/b[j]) <= log(R/mp[i][j])
即 log(L/mp[i][j]) <= log(a[i])-log(b[j]) <= log(R/mp[i][j])
得到两个不等式
log(b[j])-log(a[i]) <= -log(L/mp[i][j])
log(a[i])-log(b[j]) <= log(R/mp[i][j])
就可以用差分约束了
由于这样建边没有起点,故我们可以加上一个超级源点,让它与所有点相连,权值为0
。
#include <bits/stdc++.h>
using namespace std;
const int maxn= 400+5;
double dis[maxn];
int vis[maxn], head[maxn];
int n, m, len;
struct node{
int to,next; double w;
} e[maxn*(maxn+1)];
void Insert(int u,int v,double w){
e[++len].to = v;
e[len].w = w;
e[len].next = head[u];
head[u] = len;
}
int spfa(int s){
memset(vis, 0, sizeof(vis));
memset(dis, 0x3f, sizeof(dis));
int cnt[maxn] = {0};
queue<int>q;
q.push(s);
vis[s]=1; dis[s]=0; cnt[s]++;
while(!q.empty()){
int u=q.front(); q.pop(); vis[u]=0;
for(int i=head[u]; i; i=e[i].next){
int v=e[i].to; double w=e[i].w;
if(dis[v] > dis[u]+w){
dis[v] = dis[u]+w;
if(!vis[v]){
vis[v]=1; q.push(v); cnt[v]++;
if(cnt[v] > sqrt(n+m))//这个优化我也不知道为啥,能用就行
return 0;
}
}
}
}
return 1;
}
int main(){
double L,U,x;
while(~scanf("%d%d%lf%lf",&n, &m, &L, &U)){
len=0;
memset(head, 0, sizeof(head));
for(int i=1; i<=n; i++)
for(int j=1; j<=m; j++){
scanf("%lf", &x);//1~n表示行,n+1~n+m表示列, 我们并不用关心a[i]和b[j]的具体值是多少,只需要判断我们建好的图有没有解
Insert(n+j, i, log(U/x));
Insert(i, n+j, -log(L/x));
}
for(int i=1; i<=n+m; i++) Insert(0, i, 0);//0作为超级源点
if(spfa(0)) printf("YES
");
else printf("NO
");
}
return 0;
}