noip.ac 3276 矩阵
给定N×M的矩阵。每次可以将某一行或者某一列随便乘以一个数(可以是小数)。问能否使得所有数的都在[l,r]之间。
————————————————————————————————
每一行和每一列都可以乘上一个数,设第i行乘上H_i,第j列乘上L_j,那么原矩阵中第i行第j列a_ij变成了a_ij*H_i*L_j
所以,L / a_ij <= H_i*L_j <=R / a_ij
根据对数方程,不等式的三个部分都取LOG还成立
LOG(L / a_ij) <= LOG(H_i*L_j) <=LONG(R / a_ij)
LOG(L )-log(a_ij) <= LOG(H_i)-LOG(1/L_j) <=LONG(R )-LOG( a_ij)
然后这组不等式就变成了下面的两个:
LOG(1/L_j)- LOG(H_i)<=log(a_ij) - LOG(L )
LOG(H_i)-LOG(1/L_j) <=LONG(R )-LOG( a_ij)
把LOG(H_i)以行号建点,把LOG(1/L_j)以列号+n建点
建立0号源点,跑SPFA,看是不是有负环!
差分约束!
————————————————————————————————
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include<bits/stdc++.h> 2 using namespace std; 3 const int maxn=410; 4 int n,m,l,r; 5 double a; 6 struct edge 7 { 8 int u,v,nxt; 9 double w; 10 }e[maxn*maxn*2]; 11 int head[810],js; 12 void addage(int u,int v,double w) 13 { 14 e[++js].u=u;e[js].v=v;e[js].w=w; 15 e[js].nxt=head[u];head[u]=js; 16 } 17 double dis[810]; 18 bool inq[810]; 19 int jc[810]; 20 deque<int>q; 21 bool spfa() 22 { 23 for(int i=1;i<=n+m;++i)dis[i]=1e15; 24 q.push_back(0); 25 jc[0]++; 26 while(!q.empty()) 27 { 28 int u=q.front();q.pop_front();inq[u]=0; 29 for(int i=head[u];i;i=e[i].nxt) 30 { 31 int v=e[i].v; 32 if(dis[v]>dis[u]+e[i].w) 33 { 34 dis[v]=dis[u]+e[i].w; 35 if(inq[v]==0) 36 { 37 inq[v]=1; 38 jc[v]++; 39 if(jc[v]>n+m)return 0; 40 if(q.empty()||dis[v]<=dis[q.front()])q.push_front(v); 41 else q.push_back(v); 42 } 43 } 44 } 45 } 46 return 1; 47 } 48 double lg(double x) 49 { 50 return log(x)/log(2); 51 } 52 int main() 53 { 54 scanf("%d%d%d%d",&n,&m,&l,&r); 55 for(int i=1;i<=n;++i) 56 for(int j=1;j<=m;++j) 57 { 58 scanf("%lf",&a); 59 addage(j+n,i,lg(r)-lg(a)); 60 addage(i,j+n,lg(a)-lg(l)); 61 } 62 for(int i=1;i<=n+m;++i)addage(0,i,0); 63 puts(spfa()?"YES":"NO"); 64 return 0; 65 }