HDU-3666 THE MATRIX PROBLEM(差分约束系统判断存在与否+特殊剪枝)

来源:互联网 发布:floyd算法伪代码 编辑:程序博客网 时间:2024/06/05 13:49
题意:

给一个N*M的矩阵,是否存在两列数a1,a2,a3...an 和 b1,b2.....bm使得对矩阵中的每个数进行下面的操作之后的值在[L,U]之间,操作为:a[i] * m[i][j] / b[j]。  N,M<=400

思路:

首先能得到式子 L <= c[ij]*a[i]/b[j] <= R,然后同时除以c[ij]得 L' <= a[i]/b[j] <= R',再取log我们就得到了两个不等式:
log(a[i]) - log(b[j]) >= L'
log(a[i]) - log(b[j]) <= R'

由于a(i),b(j)都可取任何值,所以不必进行约束条件,至此所有约束条件用完了,于是建图差分约束即可。


SPFA判断负环时被卡点:
在网上看到两种优化,
(1)不必判断某一个点入队次数大于N,只要判断是否大于sqrt(1.0*N)。
(2)或者所有点的入队次数大于T*N,即存在负环,一般T取2。
其中,N为所有点的个数。

但是,第二个优化在本题就用不了,第一个的正确性也不得而知,所以做题时先正常地>N,没办法再尝试这个优化。


代码:

#include <algorithm>#include <iostream>#include <string.h>#include <cstdio>#include <queue>#include <cmath>using namespace std;const int inf = 0x3f3f3f3f;const int maxn = 805;const int maxm = 160005*2;struct node{int v, next;double w;}edge[maxm];int no, head[maxn];int vis[maxn], cnt[maxn];double dis[maxn];queue<int> q;int N, M, L, R;inline void init(){no = 0;memset(head, -1, sizeof head);}inline void add(int u, int v, double w){edge[no].v = v; edge[no].w = w;edge[no].next = head[u]; head[u] = no++;}int SPFA(){memset(vis, 0, sizeof vis);fill(dis+1, dis+N+M+1, inf);memset(cnt, 0, sizeof cnt);while(!q.empty()) q.pop();dis[1] = 0;q.push(1); vis[1] = 1;while(!q.empty()){int u = q.front(); q.pop();vis[u] = 0; ++cnt[u];if(cnt[u] > sqrt(N+M)) return -1;for(int k = head[u]; k != -1; k = edge[k].next){int v = edge[k].v;if(dis[v] > dis[u]+edge[k].w){dis[v] = dis[u]+edge[k].w;if(!vis[v]) vis[v] = 1, q.push(v);}}}return 1;}int main(){//freopen("in.txt", "r", stdin);int x;while(~scanf("%d %d %d %d", &N, &M, &L, &R)){init();for(int i = 1; i <= N; ++i)for(int j = 1; j <= M; ++j){scanf("%d", &x);double _L = log(1.0*L/x);double _R = log(1.0*R/x);add(i, N+j, -_L);add(N+j, i, _R);}if(SPFA() != -1) puts("YES");else puts("NO");}return 0;}


差分约束:当题目中存在大于某数小于某数,求两个变量之间的至少值最多值,在大于小于约束条件下的成不成功存不存在,都要尝试考虑考虑差分约束!然后再尝试构建减法,除法通过取log构建减法,但加法和乘法貌似不可行,因为对第二个数取负会是什么意义?第二个数是为了代表一个点啊!不过某些题估计也可行,遇到题目再分析吧。


继续加油~

原创粉丝点击