• 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,生命不休。。学习不止。。。

  • 相关阅读:
    【SAS NOTES】将文本转化为数据格式 input()
    【SAS NOTES】proc tabulate遇到的问题
    【SAS NOTES】proc sql
    【SAS NOTES】转载 sas函数&模块
    【SAS NOTE】substr字符串提取函数
    【SAS NOTES】输出结果到excel
    【SAS NOTES】脏数据
    【SAS NOTES】字符串处理函数
    【SAS NOTES】实际分析应用
    多项式的乘法满足结合律和交换律
  • 原文地址:https://www.cnblogs.com/wally/p/2889679.html
Copyright © 2020-2023  润新知