hdu 3666 THE MATRIX PROBLEM(差分约束系统)

感觉搞acm还是不能心急,昨天看了查分约束系统的论文后就迫不及待地做题,其实算法还没理解透。。。导致一下午的悲剧。。。回寝后冷静下来看了两小时书,今天做题明显感觉好多了。

根据这个题意,不难得出 L <= C[i][j]*a[i]/b[j] <= U的不等式,由于差分约束系统的不等式都是减法形式,对于除法变减法,显然用log函数,于是就得到了

(1) log(b[j]) - log(a[i]) <= -log(L/c[i][j])

(2) log(a[i] - log(b[j]) <= log(U/c[i][j])

这两个不等式,然后就是建图,spfa判负环,果断超时了一次。。。上网一查,如果用传统的判负环方法(判断一个点是否入队超过N次)是要超时的。。。,只需将每个节点的入队上限由N变成sqrt(N)就行,有待研究。。。用vector表示邻接表的spfa1500+ms飘过。。。有点虚。。。

    #include<iostream>
    #include<algorithm>
    #include<cmath>
    #include<queue>
    #include<vector>
    #include<cstdio>
    #include<cstring>
    using namespace std;

    const int maxn = 400 * 400 + 500;
    const double INF = 1e10;
    const double eps = 1e-8;
    int n, m, limit;
    double c, l, u;
    struct Edge
    {
        int from, to;
        double dist;
        Edge(){};
        Edge(int a, int b, double c) {from=a, to=b, dist=c;}
    };
    vector<Edge> edges;
    vector<int> G[maxn];
    int  cnt[maxn];
    double d[maxn];
    bool inq[maxn];

    void init()
    {
        for(int i=0; i<=n+m; i++)   G[i].clear();
        edges.clear();
    }

    void add(int from, int to, double dist)
    {
        Edge e = Edge(from, to, dist);
        edges.push_back(e);
        int tmp = edges.size();
        G[from].push_back(tmp-1);
    }

    bool spfa(int s)
    {
        queue<int> q;   q.push(s);
        memset(inq, 0, sizeof(inq));
        memset(cnt, 0, sizeof(cnt));
        for(int i=0; i<=n+m; i++)   d[i] = INF;
        d[s] = 0;   inq[s] = 1;     cnt[s] = 1;
        while(!q.empty())
        {
            int u = q.front();  q.pop();
            inq[u] = 0;
            for(int i=0; i<G[u].size(); i++)
            {
                Edge& e = edges[G[u][i]];
                if(d[e.to] - (d[u] + e.dist) > eps)
                {
                    d[e.to] = d[u] + e.dist;
                    if(!inq[e.to])
                    {
                        q.push(e.to);
                        inq[e.to] = 1;
                        if(++cnt[e.to] > limit)     return 1;
                    }
                }
            }
        }
        return 0;
    }

    int main()
    {
        while(~scanf("%d%d%lf%lf", &n, &m, &l, &u))
        {
            init();
            limit = (int)sqrt(1.0*(n+m));
            // limit = n+m;  这个果断超时。。。
            for(int i=1; i<=n; i++)
                for(int j=1; j<=m; j++)
                {
                    scanf("%lf", &c);
                    add(j+n, i, -log(l/c));
                    add(i, j+n, log(u/c));
                }
            if(spfa(1))  puts("NO") ;
            else    puts("YES");
        }
        return 0;
    }


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值