Time Limit: 4000/2000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 5437 Accepted Submission(s): 1372
题目意思就是是否存在ai,bj,使得l<=cij*(ai/bj)<=u (1<=i<=n,1<=j<=m)成立
首先,把cij除到两边:l'<=ai/bj<=u',如果差分约束的话,应该是ai-bj的形式,于是可以取对数
log(l')<=log(ai)-log(bj)<=log(u')
把log(ai)和log(bj)看成两个点ai和bj,化成求最短路的形式:dis[ai]-dis[bj]<=log(u'),dis[bj]-dis[ai]<=-log(l')
然后判负环就行,深搜和广搜都可以
注意,如果spfa队列判负环:
(1)不必判断某个点入队次数大于N,只要判断是否大于sqrt(1.0*N)
(2)或者所有点的入队次数大于T*N,即存在负环,一般T取2
N为所有点的个数
1, SPFA广搜:
#include<iostream> #include<cstdio> #include<cstring> #include<queue> #include<cmath> using namespace std; const int N=810; struct Edge{ int to,nxt; double cap; }edge[N*N]; int n,m,cnt,head[N]; int vis[N],Count[N]; double dis[N],L,U; void addedge(int cu,int cv,double cw){ edge[cnt].to=cv; edge[cnt].cap=cw; edge[cnt].nxt=head[cu]; head[cu]=cnt++; } int SPFA(){ int limit=(int)sqrt(1.0*(n+m)); queue<int> q; while(!q.empty()) q.pop(); memset(vis,0,sizeof(vis)); memset(Count,0,sizeof(Count)); for(int i=0;i<=n+m;i++){ dis[i]=0; q.push(i); } while(!q.empty()){ int u=q.front(); q.pop(); vis[u]=0; for(int i=head[u];i!=-1;i=edge[i].nxt){ int v=edge[i].to; if(dis[v]>dis[u]+edge[i].cap){ dis[v]=dis[u]+edge[i].cap; if(!vis[v]){ vis[v]=1; if(++Count[v]>limit) return 0; q.push(v); } } } } return 1; } int main(){ //freopen("input.txt","r",stdin); while(~scanf("%d%d%lf%lf",&n,&m,&L,&U)){ cnt=0; memset(head,-1,sizeof(head)); double x; for(int i=1;i<=n;i++) for(int j=1;j<=m;j++){ scanf("%lf",&x); addedge(j+n,i,log(U/x)); addedge(i,j+n,-log(L/x)); } if(SPFA()) puts("YES"); else puts("NO"); } return 0; }
2, SPFA深搜:(这个更快??)
#include<iostream> #include<cstdio> #include<cstring> #include<queue> #include<cmath> using namespace std; const int N=810; struct Edge{ int to,nxt; double cap; }edge[N*N]; int n,m,cnt,head[N]; int vis[N],instack[N]; double dis[N],L,U; void addedge(int cu,int cv,double cw){ edge[cnt].to=cv; edge[cnt].cap=cw; edge[cnt].nxt=head[cu]; head[cu]=cnt++; } int SPFA(int u){ if(instack[u]) return 0; instack[u]=1; vis[u]=1; for(int i=head[u];i!=-1;i=edge[i].nxt){ int v=edge[i].to; if(dis[v]>dis[u]+edge[i].cap){ dis[v]=dis[u]+edge[i].cap; if(!SPFA(v)) return 0; } } instack[u]=0; return 1; } int solve(){ memset(vis,0,sizeof(vis)); memset(instack,0,sizeof(instack)); memset(dis,0,sizeof(dis)); for(int i=1;i<=n+m;i++) if(!vis[i]){ if(!SPFA(i)) return 0; } return 1; } int main(){ //freopen("input.txt","r",stdin); while(~scanf("%d%d%lf%lf",&n,&m,&L,&U)){ cnt=0; memset(head,-1,sizeof(head)); double x; for(int i=1;i<=n;i++) for(int j=1;j<=m;j++){ scanf("%lf",&x); addedge(j+n,i,log(U/x)); addedge(i,j+n,-log(L/x)); } if(solve()) puts("YES"); else puts("NO"); } return 0; }