hdu3666差分约束
第一次做差分约束。
题意:给你一个N*M的矩阵,求两列数a1,a2,a3...an 和 b1,b2.....bm使得对矩阵中的每个数进行下面的操作之后的值在[L,U]之间,
操作为:a[i] * m[i][j] / b[j]。 N,M<=400
转:思路:差分约束。由题意可知,对于矩阵中的每个元素要满足的条件是:L <= a[i] * m[i][j] / b[j] <= U ,这样我们就可以得到下面的两个式子:L*b[j] <= a[i] * m[i][j] 和 a[i] * m[i][j] <= U*b[j] ,因为差分约束中dis[]前面没有系数,为了把系数取消掉,我们可以用对式子两遍取对数,就可以得到:log(b[j]) - log( a[i] ) <= log( m[i][j] / L) ,同理可以得到两个式子,最后用spfa判负环就可以得出答案了。
差分约束最难得是怎么建立三角不等式。
代码:
#include <iostream> #include <cmath> #include<queue> using namespace std; const int N=1000; const int M=500000; const int inf=1<<30; int vis[N],head[N],in[N]; struct node { int v,next; double w; }e[M]; int tot,n,m; double dis[N]; void add(int a,int b,double w) { e[tot].v=b; e[tot].w=w; e[tot].next=head[a]; head[a]=tot++; } bool spfa() { int i; queue<int>q; for(i=0;i<=n;i++) { dis[i]=inf; vis[i]=0; in[i]=0; } dis[1]=0; vis[1]=1; in[1]=1; q.push(1); while(!q.empty()) { int u=q.front(); q.pop(); vis[u]=0; for(i=head[u];i+1;i=e[i].next) { int v=e[i].v; double w=dis[u]+e[i].w; if(dis[v]>w) { dis[v]=w; if(!vis[v]) { vis[v]=1; if(++in[v]>(int)sqrt(n*1.0))return false;//如果是判断n次就会超时,一般每个点入队的次数不会很多,所有的入队次数大概是T*n,T大概是2左右 q.push(v); } } } } return true; } int main() { int i,l,u; while(scanf("%d%d%d%d",&n,&m,&l,&u)!=EOF) { double L,U,map; L=log(l*1.0); U=log(u*1.0); memset(head,-1,sizeof(head)); tot=0; for(i=1;i<=n;i++) { for (int j=1;j<=m;j++) { scanf("%lf",&map); map=log(map); add(i,j+n,map-L); add(n+j,i,U-map); } } n=n+m; if(spfa()) printf("YES\n"); else printf("NO\n"); } return 0; }