zoukankan      html  css  js  c++  java
  • 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表示列, 我们并不用关心a[i]和b[j]的具体值是多少,只需要判断我们建好的图有没有解
                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
    ");
            else printf("NO
    ");
        }
        return 0;
    }
    
  • 相关阅读:
    maven 常用命令
    navicat 破解
    linux命令
    Git常用命令
    关于近期工作的总结
    ES6新特性学习
    Hadoop初步学习
    串行、并行与并发的理解
    通过Spring profile方式实现多环境部署
    使用MySQL乐观锁解决超卖问题
  • 原文地址:https://www.cnblogs.com/hzoi-poozhai/p/12791654.html
Copyright © 2011-2022 走看看