hdu 3666THE MATRIX PROBLEM[差分约束]

Description
  • 给你一个M×N的矩阵,矩阵元素为不超过1000的正数,问是否存在n个数的序列a1,a2,...,an,和m个数b1,b2,...,bm,满足使第i行的每个元素乘以ai,第j列中的每个元素除以bj之后,这个矩阵中的每个元素都在LU之间,L表示元素的下界,U表示元素的上界。
Input
  • 存在多组数据
  • 每组数据第一行有四个整数N,M,L,U(1<=N,M<=400,1<=L<=U<=10000),接下来N行,每行M个整数,表示矩阵元素。
Output
  • 如果存在输出 YES,否则输出NO
Sample Input
3 3 1 6
2 3 4
8 2 6
5 2 9
Sample Output
YES

思路

这道题和差分约束有什么关系呢?

用 mp 表示矩阵

根据题意有: L<=mp[i][j]*a[i]/b[j]<=R
移项可得:   L/mp[i][j]<=a[i]/b[j]<=R/mp[i][j]
因为我们不用求出具体的值,只需判断是否满足条件,对两边取对数可以把除法变成减法
两边取对数: log(L/mp[i][j])<=log(a[i]/b[j])<=log(R/mp[i][j])
即         log(L/mp[i][j])<=log(a[i])-log(b[j])<=log(R/mp[i][j])
得到两个不等式  log(b[j])-log(a[i])<=-log(L/mp[i][j]) 
           	  log(a[i])-log(b[j])<=log(R/mp[i][j])
           就可以用差分约束了

由于这样建边没有起点,故我们可以加上一个超级源点,让它与所有点相连,权值为0

#include <bits/stdc++.h>
using namespace std;
const int maxn= 400+5;
double dis[maxn];
int vis[maxn], head[maxn];
int n, m, len;
struct node{
    int to,next; double w;
} e[maxn*(maxn+1)];
void Insert(int u,int v,double w){
    e[++len].to = v;
    e[len].w = w;
    e[len].next = head[u];
    head[u] = len;
}
int spfa(int s){
    memset(vis, 0, sizeof(vis));
    memset(dis, 0x3f, sizeof(dis));
    int cnt[maxn] = {0};
    queue<int>q;
    q.push(s);
	vis[s]=1; dis[s]=0; cnt[s]++;    
    while(!q.empty()){
        int u=q.front(); q.pop(); vis[u]=0;
        for(int i=head[u]; i; i=e[i].next){
            int v=e[i].to; double w=e[i].w;
            if(dis[v] > dis[u]+w){
                dis[v] = dis[u]+w;
                if(!vis[v]){
                    vis[v]=1; q.push(v); cnt[v]++;
                    if(cnt[v] > sqrt(n+m))//这个优化我也不知道为啥,能用就行
                        return 0;
                }
            }
        }
    }
    return 1;
}
int main(){
    double L,U,x;
    while(~scanf("%d%d%lf%lf",&n, &m, &L, &U)){
        len=0;
        memset(head, 0, sizeof(head));
        for(int i=1; i<=n; i++)
        	for(int j=1; j<=m; j++){
            	scanf("%lf", &x);//1~n表示行,n+1~n+m表示列
            	Insert(n+j, i, log(U/x));
                Insert(i, n+j, -log(L/x));
        }
        for(int i=1; i<=n+m; i++) Insert(0, i, 0);//0作为超级源点
        if(spfa(0)) printf("YES\n");
        else printf("NO\n");
    }
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/hzoi-poozhai/p/12791654.html