NKOI 2457 矩阵问题

                                                                                         P2457  矩阵问题
时间限制 : - 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<iostream>
#include<cstdio>
#include<cmath>
#include<queue>
#include<cstring>
using namespace std;
const int inf=2e9;
const int maxn=700000;
int END[maxn],NEXT[maxn],last[1005],cnt[1005],n,m,Tot;
bool flag[1005];
double X,Y,K,dis[1005],len[maxn];
void insert(int a,int b,double v){
	Tot++;
    END[Tot]=b;
    len[Tot]=v;
    NEXT[Tot]=last[a];
    last[a]=Tot;
}
bool spfa(){
	int i,a,b,t;
    for(i=1;i<=n+m;i++){
	    dis[i]=inf;
	    cnt[i]=0;
	    flag[i]=false;
	}
    dis[1]=0;
    queue<int>q;
    q.push(1);
    flag[1]=true;
	cnt[1]++;
    while(!q.empty()){
	    a=q.front();
        q.pop();
        flag[a]=false;
        t=last[a];
        while(t){
	    b=END[t];
            if(dis[b]>dis[a]+len[t]){
	     dis[b]=dis[a]+len[t];
                 if(!flag[b]){
	                  cnt[b]++;
                      if(cnt[b]>n+m)return false;
	                  flag[b]=true;
                      q.push(b);
                 }
            }
            t=NEXT[t];
        }
    }
    return true;
}
int main(){
	int T,i,j;
    scanf("%d",&T);
    while(T--){
	    Tot=0;
        memset(last,0,sizeof(last));
	    scanf("%d%d%lf%lf",&n,&m,&X,&Y);
        for(i=1;i<=n;i++)
            for(j=1;j<=m;j++){
	            scanf("%lf",&K);
                insert(i,n+j,log(K/X));
                insert(n+j,i,-log(K/Y));
            }
        if(spfa())puts("YES");
		else puts("NO");
    }
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值