差分约束,不是很难看出来
不过需要一下流氓剪枝。。。。
#include <cstdio>
#include <cstring>
#include <queue>
#include <cmath>
using namespace std;
#define swap(t,a,b) (t=a,a=b,b=t)
const int E=400000;
const int V=1001;
const double INF = 1e15;
struct EDGE
{
int link,next;
double val;
} edge[E];
int head[V],cnt[V],e;
double dist[V];
bool vis[V];
void addedge(int a,int b,double c)
{
edge[e].link=b;
edge[e].val=c;
edge[e].next=head[a];
head[a]=e++;
}
int relax(int u,int v,double c)
{
if(dist[v]>dist[u]+c)
{
//求的是最大值,若求最小值,反号
dist[v]=dist[u]+c;
return 1;
}
return 0;
}
int SPFA(int src,int n)
{
memset(vis,false,sizeof(vis));
memset(cnt,0,sizeof(cnt));
for(int i=1; i<=n; ++i) dist[i]=INF;
dist[src]=0;
vis[src]=true;
queue<int> q;
q.push(src);
++cnt[src];
int t = (int) sqrt(1.0 * n);
while(!q.empty())
{
int u,v;
u=q.front();
q.pop();
vis[u]=false;
for(int i=head[u]; i!=-1; i=edge[i].next)
{
v=edge[i].link;
if(relax(u,v,edge[i].val)==1&&!vis[v])
{ //如果不用relax函数,!VIS[V]的判断应该写在这
q.push(v);
vis[v]=true;
if((++cnt[v])>t) return -1;//cnt[i]为入队列次数,用来判断是否存在负权回路
}
}
}
if(dist[n]==INF) return -2;
// src与n不可达,有些题目可省!!!
return 1;
//返回src到n的最短距离,根据题意不同而改变
}
int main()
{
int n, m, l, u;
while(scanf("%d%d%d%d", &n, &m, &l, &u) != EOF)
{
e=0;
memset(head,-1,sizeof(head));
//a 1...n
for(int i = 1; i <= n; i++)
{
int x;
for(int j = 1; j <= m; j++)
{
scanf("%d", &x);
addedge(i, j + n, log(1.0 * u / x));
addedge(j + n, i, log(1.0 * x / l));
}
}
int ans = SPFA(1, n + m);
if(ans == -1 || ans == -2) printf("NO\n");
else printf("YES\n");
}
return 0;
}