给出一个n*m的整数矩阵F。矩阵中第i行第j列的元素表示为F[i][j] 1<=i<=n, 1<=j<=m。
求两个数列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<=N、M<=400,1<=X<=Y<=20000
给出的矩阵中每个数字都是1000以内的正整数。
这道题有不等关系,显然是差分约束。但是如何建图是个很严重的问题。
首先要明确的一点是:差分约束的式子x-y<=k中x,y前的系数都必须是1,而且k必须是常数。(我就是因为这一点没有把式子化简出来,可恶)
题目中F[i][j]和x,y都是常数,所以它们肯定要放在式子的右边。以A[i] * F[i][j] / B[j] <= Y 为例,A[i] / B[j] <= Y / F[i][j]. 变成减法当然是取对数!!!这道题敲个板就完了,所以还是比较简单的。
数组不要开小了。
#include
#include
#include
#include
#include
#define D double
#define E 500000
#define N 1000
using namespace std;
int End[E],Last[E],Next[E],cnt,Pnum,ti[N];
D Len[E],dis[N];bool used[N];
void Init(){
for(int i=0;i0;Len[i]=0;}
for(int i=0;i0,ti[i]=0;
cnt=0;
}
void Ins(int x,int y,D w){
End[++cnt]=y,Len[cnt]=w;
Next[cnt]=Last[x],Last[x]=cnt;
}
bool SPFA(int s){
for(int i=1;i<=Pnum;i++)dis[i]=(D)1e9;
queue<int>q;q.push(s);
dis[s]=0,ti[s]++,used[s]=true;
while(!q.empty()){
int u=q.front();q.pop();used[u]=false;
for(int i=Last[u];i;i=Next[i]){
int v=End[i];
if(dis[v]>dis[u]+Len[i]){
dis[v]=dis[u]+Len[i];
if(!used[v]){
if(++ti[v]>Pnum)return false;
used[v]=true,q.push(v);
}
}
}
}
return true;
}
int main(){
int t;scanf("%d",&t);
while(t--){
int n,m,x,y;D xx,yy;
scanf("%d%d%d%d",&n,&m,&x,&y);
xx=log2(x),yy=log2(y);
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++){
int t;scanf("%d",&t);D tt=log2(t);
Ins(i,j+n,tt-xx),Ins(j+n,i,yy-tt);
}
Pnum=n+m;
if(SPFA(1))puts("YES");
else puts("NO");
Init();
}
return 0;
}