D 矩阵问题
时间限制 : - 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] 和 a[i] * F[i][j] <= Y*b[j] ,
因为差分约束中dis[]前面没有系数,为了把系数取消掉,我们可以用对式子两遍取对数,
就可以得到:
log(b[j]) - log( a[i] ) <= log( F[i][j] / X) ,
log(a[i]) - log( b[j] ) <= -log( F[i][j] / Y)
同理可以得到两个式子,最后用spfa判负环就可以得出答案了。
N为所有点的个数
代码如下:
#include<cstdio>
#include<iostream>
#include<cstring>
#include<queue>
#include<vector>
#include<cmath>
#define LL int
#define CLEAR(XXX) memset((XXX),0,sizeof(XXX))
using namespace std;
const LL inf=2e9;
const int maxn=1005,maxm=700005;
int n,m,x,y;
struct Edge{
int from,to;
double w;
Edge(int from,int to,double w):from(from),to(to),w(w){}
};
struct SPFA{
int n,m;
vector<Edge> edge;
int last[maxm],Next[maxm];
double dist[maxn];
int cnt[maxn];
bool vis[maxn];
void init(int n){
this->n = n;
m=0;
CLEAR(last); CLEAR(Next);
edge.clear();
edge.push_back(Edge(0,0,0));
}
void add_edge(int from,int to,double dist){
edge.push_back(Edge(from,to,dist));
m=edge.size()-1;
Next[m]=last[from];
last[from]=m;
}
bool solve(int s){
int i;
CLEAR(vis); CLEAR(cnt);
for(i=1;i<=n;i++) dist[i]=inf;
dist[s]=0;
vis[s]=true;cnt[s]++;
queue <int> q;
q.push(s);
while(!q.empty()){
int x=q.front();
q.pop();vis[x]=false; //及时修改标记
for(i=last[x];i;i=Next[i]){
Edge& e=edge[i];
if(dist[e.from]+e.w<dist[e.to]){
dist[e.to]=dist[e.from]+e.w;
if(!vis[e.to]){
cnt[e.to]++; //统计入队次数,判断负权回路
if(cnt[e.to]==n+1)return false;
q.push(e.to) ;
vis[e.to]=true;
}
}
}
}
return true;
}
};
SPFA solver ;
int main(){
int T,i,j;
double t;
scanf("%d",&T);
while(T--){
scanf("%d%d%d%d",&n,&m,&x,&y);
solver.init(n+m);
for(i=1;i<=n;i++)
for(j=1;j<=m;j++){
scanf("%lf",&t);
solver.add_edge(i,n+j,log(t/x));
solver.add_edge(n+j,i,-log(t/y));
}
if(solver.solve(1)) puts("YES");
else puts("NO");
}
return 0;
}