hdu 3666 差分约束系统

这也是我第一次碰到差分约束的题。。。

好吧。。。赶紧学一下吧。。

差分约束系统:

假设有这样一组不等式:

x1-x2<=0;

x1-x5<=-1;

x2-x5<=1;

x3-x1<=5;

x4-x1<=4;

x4-x3<=-1;

。。。。

每个不等式都是有两个未知数的差小于等于某个常数(大于等于也可以,只要两边同乘以-1就可以了),这样的不等式组就称作差分约束系统(这个不等式组要么无解,要么有无数组解,因为若(x1,x2,x3....)是一组解,那么(x1+k,x2+k,x3+k,...)也必然是一组解);

差分约束系统与最短路径的关系:

差分约束系统的求解可以利用单源最短路径中的三角不等式,即对于边<u,v>都有dist[v]<=dist[u]+edge[u][v];

于是上面的不等式就可以化为dist[v]-dist[u]<=edge[u][v],从而就把一个差分约束系统转化为了一个图;

<构造方法>

1、不等式中的每个未知数都对应图中的一个顶点;

2、把所有的不等式都化为图中的一条边,对于不等式xi-xj<=c,就可以化为边<vi,vj>,其中权值为c;

于是,对于hdu 3666这题:

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

首先   L<= c[i][j] *ai / bj  <= u , 我们遇到的都是减法的差分约束,那么我们取log就可以了,两边同除以 c[i][j] ,  然后取 log  锝 ,log(l) - log(c[i][j]) <= log(a) - log(b) <= log(u) - log(c[i][j]) ;  然后 SPFA判断是否有负环,如果存在,则说明无解。

判断有无解(负环)的时候,如果用spfa,不能用入队次数大于N来判断,会超时。

有如下两种比较可靠的方法(一般情况下)

1:某个点入队次数大于sqrt(N)的时候

2:所有入队次数大于T * (N + M),其中T一般取2。。。

好吧。。。到这儿也差不多了,我就直接上代码了。。。

View Code
 1 #include<iostream>

 2 #include<queue>

 3 #include<cstring>

 4 #include<cmath>

 5 const int N=1000;

 6 const double inf=1e10;

 7 using namespace std;

 8 

 9 double dist[N];

10 int head[N];

11 int visited[N];

12 int _count[N];//用来记录同一个点入队列的次数

13 int n,m,cnt;

14 

15 struct point {

16     int v,next;

17     double w;//终点、权值、以及指向下一条边

18 }edge[N*N];

19 

20 void CreateMap(int u ,int v,double w){

21     edge[cnt].v=v;

22     edge[cnt].w=w;

23     edge[cnt].next=head[u];

24     head[u]=cnt++;

25 }

26 

27 int  SPFA(){

28     memset(visited,0,sizeof(visited));

29     memset(_count,0,sizeof(_count));

30     for(int i=1;i<=n+m;i++){

31         dist[i]=inf;

32     }

33     dist[1]=0;

34     visited[1]=1;

35     _count[1]++;

36     queue<int>Q;

37     Q.push(1);

38     while(!Q.empty()){

39         int tmp=Q.front();

40         Q.pop();

41         visited[tmp]=0;

42         for(int i=head[tmp];i!=-1;i=edge[i].next){

43             if(dist[tmp]+edge[i].w<dist[edge[i].v]){

44                 dist[edge[i].v]=dist[tmp]+edge[i].w;

45                 if(!visited[edge[i].v]){

46                     Q.push(edge[i].v);

47                     visited[edge[i].v]=1;

48                     if(++_count[edge[i].v]>(int)sqrt(1.0*(n+m)))//同一个点入队列次数超过sqrt(n+m)次,就说明无解

49                         return 0;

50 

51                 }

52             }

53         }

54     }

55     return 1;

56 }

57 

58 

59 int main(){

60     int temp;

61     double l,u;

62     while(scanf("%d%d",&n,&m)!=EOF){

63         memset(head,-1,sizeof(head));

64         scanf("%lf%lf",&l,&u);

65         cnt=1;

66         for(int i=1;i<=n;i++){

67             for(int j=1;j<=m;j++){

68                 scanf("%d",&temp);

69                 CreateMap(i,j+n,-log(l*1.0/temp));

70                 CreateMap(j+n,i,log(u*1.0/temp));

71             }

72         }

73         int flag=SPFA();

74         if(flag){

75             printf("YES\n");

76         }else

77             printf("NO\n");

78     }

79     return 0;

80 }

好吧,明天继续差分约束系统。。。orz,生命不休。。学习不止。。。

 

你可能感兴趣的:(差分约束)