hdu 3666(差分约束,手动栈解决超时问题)

THE MATRIX PROBLEM

Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 8016    Accepted Submission(s): 2092

Problem Description

You have been given a matrix CN*M, each element E of CN*M
is positive and no more than 1000, The problem is that if there exist N
numbers a1, a2, … an and M numbers b1, b2, …, bm, which satisfies that
each elements in row-i multiplied with ai and each elements in column-j
divided by bj, after this operation every element in this matrix is
between L and U, L indicates the lowerbound and U indicates the
upperbound of these elements.

Input

There are several test cases. You should process to the end of file.
Each
case includes two parts, in part 1, there are four integers in one
line, N,M,L,U, indicating the matrix has N rows and M columns, L is the
lowerbound and U is the upperbound
(1<=N、M<=400,1<=L<=U<=10000). In part 2, there are N
lines, each line includes M integers, and they are the elements of the
matrix.

Output

If there is a solution print "YES", else print "NO".

Sample Input

3 3 1 6
2 3 4
8 2 6
5 2 9

Sample Output

YES

Source

2010 Asia Regional Harbin

题意:给出一个矩阵 C 问是否存在这样两个序列使得  l <= cij * ai/bj <= r 对这个矩阵成立。

题解:将cij除过去,然后取个对数, log(l/cij) <= log(ai) - log(bj) <= log(r/cij) 这样的话就可以化为一个差分约束的题了,但是这个题有个问题就是判环会超时,有人提出可以只判断sqrt(n)次就行了,,但是无法证明,这个题的更好的方法是用一个手动栈代替队列.这样的话就能够快速判环了,给出两份代码..

只用sqrt(n)的队列写法:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
#include<math.h>
using namespace std;
const double INF = 999999999;
const int N = 805;
const int M = 800000;
struct Edge{
    int v,next;
    double w;
}edge[M];
int head[N],tot;
int n,m,l,r;
void init(){
    memset(head,-1,sizeof(head));
    tot = 0;
}
void addEdge(int u,int v,double w,int &k){
    edge[k].v =v ,edge[k].w = w ,edge[k].next = head[u],head[u] = k++;
}
double low[N];
int time[N];
bool vis[N];
bool spfa(int s){
    for(int i=0;i<=n+m;i++){
        vis[i] = false;
        time[i] = 0;
        low[i] = INF;
    }
    int num = ((int)sqrt(n+m))+1;
    low[s] = 0;
    time[s]++;
    queue<int>q;
    q.push(s);
    while(!q.empty()){
        int u = q.front();
        q.pop();
        vis[u] = false;
        for(int k=head[u];k!=-1;k=edge[k].next){
            int v = edge[k].v;
            double w = edge[k].w;
            if(low[v]>low[u]+w){
                low[v] = low[u]+w;
                if(!vis[v]){
                    vis[v] = true;
                    q.push(v);
                    time[v]++;
                    if(time[v]>num) return false;
                }
            }
        }
    }
    return true;
}
int main()
{
    double c;
    while(scanf("%d%d%d%d",&n,&m,&l,&r)!=EOF){
        init();
        for(int i=1;i<=n;i++){
            for(int j=1;j<=m;j++){
                scanf("%lf",&c);
                addEdge(i,n+j,-log(l/c),tot);
                addEdge(n+j,i,log(r/c),tot);
            }
        }
        for(int i=1;i<=n+m;i++){
            addEdge(0,i,0,tot);
        }
        if(spfa(0)) printf("YES\n");
        else printf("NO\n");
    }
    return 0;
}

手动栈解决:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
#include<math.h>
using namespace std;
const double INF = 999999999;
const int N = 805;
const int M = 800000;
struct Edge{
    int v,next;
    double w;
}edge[M];
int head[N],tot;
int n,m,l,r;
void init(){
    memset(head,-1,sizeof(head));
    tot = 0;
}
void addEdge(int u,int v,double w,int &k){
    edge[k].v =v ,edge[k].w = w ,edge[k].next = head[u],head[u] = k++;
}
double low[N];
int time[N];
bool vis[N];
int stk[N*N];
bool spfa(int s){
    for(int i=0;i<=n+m;i++){
        vis[i] = false;
        time[i] = 0;
        low[i] = INF;
    }
    int top = 0;
    low[s] = 0;
    time[s]++;
    stk[top++] = s;
    while(top!=0){
        int u = stk[--top];
        vis[u] = false;
        for(int k=head[u];k!=-1;k=edge[k].next){
            int v = edge[k].v;
            double w = edge[k].w;
            if(low[v]>low[u]+w){
                low[v] = low[u]+w;
                if(!vis[v]){
                    vis[v] = true;
                    stk[top++] = v;
                    time[v]++;
                    if(time[v]>n+m) return false;
                }
            }
        }
    }
    return true;
}
int main()
{
    double c;
    while(scanf("%d%d%d%d",&n,&m,&l,&r)!=EOF){
        init();
        for(int i=1;i<=n;i++){
            for(int j=1;j<=m;j++){
                scanf("%lf",&c);
                addEdge(i,n+j,-log(l/c),tot);
                addEdge(n+j,i,log(r/c),tot);
            }
        }
        for(int i=1;i<=n+m;i++){
            addEdge(0,i,0,tot);
        }
        if(spfa(0)) printf("YES\n");
        else printf("NO\n");
    }
    return 0;
}
时间: 2024-10-14 00:41:07

hdu 3666(差分约束,手动栈解决超时问题)的相关文章

Candies(差分约束_栈+SPFA)

CandiesCrawling in process... Crawling failed Time Limit:1500MS     Memory Limit:131072KB     64bit IO Format:%I64d & %I64u Submit Status Description During the kindergarten days, flymouse was the monitor of his class. Occasionally the head-teacher b

hdu 1364(差分约束)

King Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 12056   Accepted: 4397 Description Once, in one kingdom, there was a queen and that queen was expecting a baby. The queen prayed: ``If my child was a son and if only he was a sound kin

Instrction Arrangement (hdu 4109 差分约束)

Instrction Arrangement Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 1395    Accepted Submission(s): 584 Problem Description Ali has taken the Computer Organization and Architecture course th

hdu 1534(差分约束)

Schedule Problem Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Submission(s): 1715    Accepted Submission(s): 757Special Judge Problem Description A project can be divided into several parts. Each part shoul

差分约束+SPFA+栈

#include <stdio.h> #include <string.h> #include <queue> #include <stack> #define INF 0x3f3f3f3f using namespace std; struct node { int u,v,w,next; }edge[150001]; int head[30001],dis[30001],vis[30001],k,n,m,s; void add(int u,int v,i

怎么搞差分约束?

差分约束是用来解多个不等式中一个什么玩意儿的MAX或MIN 或者是这么一大堆式子有没有解 v - u > x     巴拉巴拉好多这样的式子 看一下最短路是如何运作的 在一张已经维护好的图上 有dis[v]<=dis[u]+way[u][v]; 把上面的式子Duang Duang Duang一顿转换后得到 u - v < -x u < v + (- x) 实现到图上就是 addedge( u, v , -x)  从u到v连一条边 长度为dis 表示从v 至少比 u 大 -x; (其

Hdu 3666 THE MATRIX PROBLEM(差分约束)

题目地址:http://acm.split.hdu.edu.cn/showproblem.php?pid=3666 思路:差分约束. 取对数将乘除转化为加减. L<=m[i][j]*a[i]/b[j]<=U log(L/m[i][j])<=log(a[i])-log(b[j])<=log(U/m[i][j]) 则 : log(a[i])<=log(b[j])+log(U/m[i][j]) log(b[j])<=log(a[i])+log(m[i][j]/L) SPFA判

HDU 3666 THE MATRIX PROBLEM (差分约束)

题意:给定一个最大400*400的矩阵,每次操作可以将某一行或某一列乘上一个数,问能否通过这样的操作使得矩阵内的每个数都在[L,R]的区间内. 析:再把题意说明白一点就是是否存在ai,bj,使得l<=cij*(ai/bj)<=u (1<=i<=n,1<=j<=m)成立. 首先把cij先除到两边去,就变成了l'<=ai/bj<=u',由于差分约束要是的减,怎么变成减法呢?取对数呗,两边取对数得到log(l')<=log(ai)-log(bj)<=l

hdu 差分约束题集

[HDU]1384 Intervals 基础差分约束★1529 Cashier Employment 神级差分约束★★★★ 1531 King 差分约束★1534 Schedule Problem 差分约束输出一组解★3440 House Man 比较好的差分约束★★3592 World Exhibition 简单★3666 THE MATRIX PROBLEM 中等★★4274 Spy's Work [先处理出欧拉序列,然后就是差分约束了...] [POJ]1201 Intervals1275