THE MATRIX PROBLEM
Total Submission(s): 7644 Accepted Submission(s): 1973
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.
3 3 1 6 2 3 4 8 2 6 5 2 9
YES
题意:给你一个 N*M 的矩阵 x[N][M],问是否存在这样的两个序列( a[1], a[2], a[3], …… a[N] ),( b[1], b[2], b[3], …… b[M] ),使得对于任意的 x[i][j],都有 L <= x[i][j] * a[i] / b[j] <= U。
分析;差分约束问题。
差分约束:即对于给定的不等式 a - b <= c,对应于最短路中的 d[v] <= d[u] + dist[u][v] 这条性质,可以连边 b -> a,边权为 c;这样对于多组不等式连边构图之后,得到源点到每个点的最短路即为不等式的最小解。而如果图中存在负圈,那么无解。
此题也可以演变为差分约束问题,对不等式进行变形可得:L / x[i][j] <= a[i] / b[j] <= U / x[i][j];如何把它变成相减的形式呢?可以两边同时取对数,即可得:log(a[i]) - log(b[j]) <= log(U / x[i][j]), log(b[j]) - log(a[i]) <= -log(L / x[i][j]);那么可以得到两组边( j + N, i, log(U / x[i][j]) ),( i, j + N, -log(L / x[i][j]) ); 图建好后,跑最短路判断即可。但是此题就在此会出问题了,spfa判断负圈,是单点入队次数超过 N+M 次即可判定为存在负圈,如果用最原始的spfa会超时,这里用SLF优化后即可过。SLF:设当前点为 v,队首元素为u,若dist[v] < dist[u],即把 v 加入到队列的头部,否则加入到队列尾部。
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3666
代码清单:
#include <map>
#include <set>
#include <cmath>
#include <queue>
#include <stack>
#include <ctime>
#include <vector>
#include <cctype>
#include <string>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <algorithm>
using namespace std;
#define end() return 0
typedef long long ll;
typedef unsigned int uint;
typedef unsigned long long ull;
const int maxn = 400 + 5;
const double maxd = 1000000000.0 + 5.0;
struct Edge
{
int to;
int next;
double dis;
};
int N, M, L, U;
int x[maxn][maxn];
int num;
int head[maxn * 2];
Edge graph[maxn * maxn * 2];
double d[maxn * 2];
int cnt[maxn * 2];
bool vis[maxn * 2];
void init(){
memset(graph, 0, sizeof(graph));
memset(head, -1, sizeof(head));
num = 0;
}
void addEdge(int u, int v, double dis){
graph[num].to = v;
graph[num].dis = dis;
graph[num].next = head[u];
head[u] = num++;
}
void input(){
for(int i = 1; i <= N; i++){
for(int j = 1; j <= M; j++){
scanf("%d", &x[i][j]);
}
}
}
void createGraph(){
for(int i = 1; i <= M + N; i++) addEdge(0, i, 0.0);
for(int i = 1; i <= N; i++){
for(int j = 1; j <= M; j++){
addEdge(N + j, i, log(1.0 * U / x[i][j]));
addEdge(i, N + j, -log(1.0 * L / x[i][j]));
}
}
}
bool spfa(){
fill(d, d + 1 + M + N, maxd);
memset(vis, false, sizeof(vis));
memset(cnt, 0, sizeof(cnt));
d[0] = 0.0;
cnt[0] = 1;
vis[0] = true;
deque <int> q;
q.push_front(0);
while(!q.empty()){
int u = q.front(); q.pop_front();
vis[u] = false;
for(int i = head[u]; i != -1; i = graph[i].next){
int v = graph[i].to;
double dis = graph[i].dis;
if(d[v] > d[u] + dis){
d[v] = d[u] + dis;
if(!vis[v]){
vis[v] = true;
cnt[v]++;
if(cnt[v] >= N + M) return false;
if(!q.empty()){
if(d[v] < d[q.front()]) q.push_front(v);
else q.push_back(v);
}
else q.push_front(v);
}
}
}
}return true;
}
void solve(){
createGraph();
if(spfa()) puts("YES");
else puts("NO");
}
int main(){
while(scanf("%d%d%d%d", &N, &M, &L, &U) != EOF){
init();
input();
solve();
} end();
}