NKOJ 2457 矩阵问题
时间限制 : - MS 空间限制 : 165536 KB
评测说明 : 时限:3000ms
问题描述
给出一个n*m的整数矩阵F。
求两个数列A和B,数列A有n个元素:A1,A2,A3…An 。数列B有m个元素:B1,B2,B3…..Bm,
使得对矩阵中的每个数进行下面的计算之后的结果在[X,Y]之间:
计算操作为:A[i] * F[i][j] / B[j]。
输入格式
第一行, 一个整数T(T<=5),表示有T组测试数据
对于每组测试数据:
第一行,四个整数n,m,X,Y
接下来一个n*m的矩阵,数字间以空格做间隔
输出格式
共T行,每行对应一组测试数据的结果:
若能找到满足条件的数列A和B,输出“YES”,否则输出“NO”
样例输入 1
2
3 3 1 6
2 3 4
8 2 6
5 2 9
3 5 8 9
13 12 4 7 5
10 10 13 9 13
3 15 4 5 11
样例输出 1
YES
NO
样例输入 2
2
4 7 2 4
11 10 8 15 8 1 12
8 2 2 8 13 12 2
6 10 9 7 11 10 1
5 9 9 11 7 10 9
3 10 1 11
18 8 18 14 12 6 7 17 15 12
14 3 4 17 8 1 19 4 6 1
8 20 4 7 19 19 6 15 6 16
样例输出 2
NO
YES
提示
1<=N、M<=400,1<=X<=Y<=20000
给出的矩阵中每个数字都是1000以内的正整数。
思路:
题目为关于不等式的题考虑使用差分约束。
题意 x<=a[i]*F[i][j]/b[j]<=y
移项得 x*b[j]<=a[i]*F[i][j]<=y*b[j]
该形式不满足差分约束的形式,所以(方法)两边同时取对数
则原式化为 log(x*b[j])<=log(a[i]*F[i][j])<=log(y*b[j])
log(x)+log(b[j])<=log(a[i])+log(F[i][j])<=log(y)+log(b[j])
则可得到两个不等式:
log(b[j])-log(a[i])<=log(F[i][j])-log(x)
log(a[i])-log(b[j])<=log(y)-log(F[i][j])
设dis[i]表示log(a[i])
dis[j+n]表示log(b[j])
使用差分约束,则当出现负权回路时无解
代码:
#include<iostream>
#include<cstdio>
#include<queue>
#include<cmath>
using namespace std;
const int needb=320007;
const int needd=807;
const int inf=100000000;
queue<int>q;
bool f[needd];
int tot=0,fi[needb],la[needb],en[needb],cnt[needd];
double le[needb],dis[needd];
double x,y;
int n,m;
void add_(int b,int a,double c)
{
tot++;
le[tot]=c;
en[tot]=b;
la[tot]=fi[a];
fi[a]=tot;
}
bool spfa()
{
int x,y,t;
for(int i=1;i<=n+m;i++)
{
dis[i]=inf;
f[i]=false;
cnt[i]=0;
}
while(q.size()) q.pop();
q.push(1);f[1]=true;dis[1]=0,cnt[1]++;
while(q.size())
{
x=q.front();f[x]=false;q.pop();
t=fi[x];
while(t!=0)
{
y=en[t];
if(dis[x]+le[t]<dis[y])
{
dis[y]=dis[x]+le[t];
if(!f[y])
{
q.push(y);f[y]=true;
cnt[y]++;
if(cnt[y]>m+n) return false;
}
}
t=la[t];
}
}
return true;
}
int main()
{
int t;scanf("%d",&t);
while(t)
{
t--;
scanf("%d%d%lf%lf",&n,&m,&x,&y);
x=log(x),y=log(y);
double a;
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
{
scanf("%lf",&a);
a=log(a);
add_(n+j,i,a-x);
add_(i,n+j,y-a);
}
printf(spfa()?"YES\n":"NO\n");
for(int i=1;i<=tot;i++)
{
la[i]=le[i]=en[i]=0;
}
for(int i=1;i<=n+m;i++) fi[i]=0;
tot=0;
}
}