题目请戳这里

题目大意:给一个n*m的矩阵,求是否存在这样两个序列:a1,a2。。。an,b1,b2,。。。,bm,使得矩阵的第i行乘以ai,第j列除以bj后,矩阵的每一个数都在L和U之间。

题目分析:比较裸的差分约束。考虑那2个序列,可以抽象出m+n个点。乘除法可以通过取对数转换为加减法。然后就可以得到约束关系:

对于矩阵元素cij,有log(L) <= log(cij) + ai - bj <= log(U),整理可得:

ai - bj <= log(U) - log(cij),n+j向i建边,边权log(U) - log(cij)。

bj - ai<= log(cij) - log(L),i向n+j建边,边权log(cij) - log(L)。

设0为源点,源点到每个点建边,边权0。从源点出发找负环,存在负环无解。

求最短路一般用spfa比较高效,但是如果判断负环的话spfa就比较慢了,因为最坏情况下复杂度依然是O(m*n)的,这题如果用spfa判断一个点进队n+m次就会TLE。一个不严谨的结论是判断sqrt(n+m)次就可以了。

判断负环还有一种更高效的方法:dfs。利用dfs深度优先的特点,找到一条路就一直往下走,能很快找出负环。每次访问一个节点后标记进栈,如果访问到某个点发现已经被标记进栈了,可以直接判断负环。

详情请见代码(二合一):

#include <iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
const int N = 405;
const int M = 805;
const double eps = 1e-7; double c[N][N];
int l,r,n,m,num;
double la,ra;
struct node
{
int to,next;
double val;
}g[10000005];
int head[M],in[M],que[M];
double dis[M];
bool flag[M];
void build(int s,int e,double v)
{
g[num].to = e;
g[num].next = head[s];
g[num].val = v;
head[s] = num ++;
}
bool instack[M];
bool dfs(int cur)
{
if(instack[cur])
return true;
instack[cur] = true;
flag[cur] = true;//visted
int i;
for(i = head[cur];~i;i = g[i].next)
if(dis[cur] + g[i].val < dis[g[i].to])
{
dis[g[i].to] = dis[cur] + g[i].val;
if(dfs(g[i].to))
return true;
}
instack[cur] = false;
return false;
}
bool dspfa()
{
int i;
memset(flag,false,sizeof(flag));
memset(instack,false,sizeof(instack));
for(i = 0;i <= m + n;i ++)
{
dis[i] = 0.0;
}
for(i = 1;i <= m + n;i ++)
if(!flag[i])
if(dfs(i))
return true;
return false;
} bool spfa()
{
int i;
int front,rear;
front = rear = 0;
for(i = 0;i <= m + n;i ++)
{
dis[i] = 100000000.0;
flag[i] = false;
in[i] = 0;
}
dis[0] = 0;
in[0] = 1;
flag[0] = true;
que[rear ++] = 0;
while(front != rear)
{
int u = que[front ++];
if(front == M)
front = 0;
flag[u] = false;
for(i = head[u];~i;i = g[i].next)
{
if(dis[g[i].to] > dis[u] + g[i].val)
{
dis[g[i].to] = dis[u] + g[i].val;
if(flag[g[i].to] == false)
{
flag[g[i].to] = true;
in[g[i].to] ++;
if(in[g[i].to] > (n + m))//sqrt((double)
return false;
que[rear ++] = g[i].to;
if(dis[que[front]] > dis[g[i].to])
swap(que[front],que[rear - 1]);
if(rear == M)
rear = 0;
}
}
}
}
return true;
}
int main()
{
//freopen("out.txt","r",stdin);
int i,j,x;
while(scanf("%d",&n) != EOF)
{
scanf("%d%d%d",&m,&l,&r);
la = log10((double)l);ra = log10((double)r);
memset(head,-1,sizeof(head));
num = 1;
for(i = 1;i <= n + m;i ++)
build(0,i,0.0);
for(i = 1;i <= n;i ++)
for(j = 1;j <= m;j ++)
{
scanf("%d",&x);
c[i][j] = log10((double)x);
build(i,j + n,c[i][j] - la);
build(j + n,i,ra - c[i][j]);
}
if(spfa())//if(!dspfa())
puts("YES");
else
puts("NO");
}
return 0;
}
//671MS 6620K
//312MS 6616K

最新文章

  1. Android Fragment---执行Fragment事务
  2. BZOJ 1227 【SDOI2009】 虔诚的墓主人
  3. spring代理模式 service远程调用,插件执行
  4. POJ2195 Going Home
  5. 如何给zencart安装image handler插件?
  6. SQL2005中的事务与锁定(四)- 转载
  7. 面向服务的体系结构(SOA)——(5)关于MEP(Message Exchange Patterns)
  8. 其他常用HTML 片段
  9. Android HandlerThread 使用
  10. .net 加水印 图片变大很多 解决方法
  11. 阅读zepto.js的core中的Core methods
  12. java中的重载与重写
  13. Springmvc 视频学习地址
  14. zabbix监控特定脚本有无生成
  15. access数据库之cookie注入
  16. Python Rabbit 广播模式
  17. 二分图带权匹配 KM算法与费用流模型建立
  18. NDK编译常用命令及不同版本so编译方法
  19. Codeforces Round #462 (Div. 2) B-A Prosperous Lot
  20. 剑指offer-顺时针打印矩阵-二维数组

热门文章

  1. java中集合类的简介
  2. c-连接两个链表
  3. big_table练习数据表
  4. Android获取屏幕的高度和宽度
  5. IE8’s Substr() Bug
  6. 激活office 2013
  7. 文成小盆友python-num7 -常用模块补充 ,python 牛逼的面相对象
  8. C程序设计语言练习题1-23
  9. SCJP_104——题目分析(4)
  10. SPRING-MVC访问静态文件,如jpg,js,css