【题】【差分约束】NKOJ 2457 矩阵问题

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;
    }
} 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值