zoukankan      html  css  js  c++  java
  • POJ 1364 / HDU 3666 【差分约束-SPFA】

    POJ 1364

    题解:最短路式子:d[v]<=d[u]+w

    式子1:sum[a+b+1]sum[a]>c      —      sum[a]<=sum[a+b+1]c1       —      (a+b+1,a) c1

    式子2:sum[a+b+1]sum[a]<c      —      sum[a+b+1]<=sum[a]+c1       —      (a,a+b+1)  c1

    注意:先移项,移项完后再处理没有等于的情况。

    附加式:sum[0]<=sum[i]+0  —— (i,0) 0 连通所有点

     1 #include <queue>
     2 #include <cstdio>
     3 #include <cstring>
     4 #include <iostream>
     5 #include <algorithm>
     6 using namespace std;
     7 
     8 const int N=105;
     9 const int INF=0x3f3f3f3f;
    10 int n,m,cnt;
    11 int head[N],d[N],Time[N];
    12 bool vis[N];
    13 
    14 struct edge{
    15     int to,next,w;
    16 }edge[N<<1];
    17 
    18 void add(int u,int v,int w){
    19     edge[cnt].w=w;edge[cnt].to=v;edge[cnt].next=head[u];head[u]=cnt++;
    20 }
    21 
    22 void init(){
    23     cnt=0;
    24     memset(Time,0,sizeof(Time));
    25     memset(head,-1,sizeof(head));
    26 }
    27 
    28 bool SPFA(int st){
    29     for(int i=0;i<N;i++) d[i]=INF;
    30     memset(vis,false,sizeof(vis));
    31     queue <int> Q;
    32     Q.push(st);
    33     d[st]=0;
    34     vis[st]=true;
    35     Time[st]=1;
    36     while(!Q.empty()){
    37         int u=Q.front();
    38         Q.pop();
    39         vis[u]=false;
    40         for(int i=head[u];i!=-1;i=edge[i].next){
    41             int v=edge[i].to;
    42             if(d[v]>d[u]+edge[i].w){
    43                 d[v]=d[u]+edge[i].w;
    44                 if(!vis[v]){
    45                     Q.push(v);
    46                     vis[v]=true;
    47                     Time[v]++;
    48                     if(Time[v]>n) return false;
    49                 }
    50             }
    51         }
    52     }
    53     return true;
    54 }
    55 
    56 int main(){
    57     while(scanf("%d",&n)!=EOF&&n){
    58         init();
    59         scanf("%d",&m);
    60         // 约束:s[0]<=s[i]+0
    61         for(int i=1;i<=n;i++) add(i,0,0);// 保证所有点连通 
    62         char op[10];
    63         for(int i=1;i<=m;i++){
    64             int a,b,c;
    65             scanf("%d%d%s%d",&a,&b,&op,&c);
    66             if(op[0]=='g') add(a+b,a-1,-c-1);
    67             else add(a-1,a+b,c-1);
    68         }
    69         if(SPFA(0)) printf("lamentable kingdom
    ");
    70         else printf("successful conspiracy
    ");
    71     }
    72     return 0;
    73 }

    HDU 3666

    题解:由题意得:L<=c[i][j]a[i]/b[j]<=两边除以c[i][j]c[i][j]    —    L/c[i][j]<=a[i]/b[j]<=U/c[i][j],先两边取对数,得到log(L/c[i][j])<=log(a[i])log(b[j])<=log(U/c[i][j]),推导出两个式子:

    式子1:log(a[i])<=log(U/c[i][j])+log(b[j])

    式子2:log(b[j])<=log(a[i])log(L/c[i][j])

    注意:log取double型,n个a和m个b连接,保证了图的连通性,不需要新建边。数据范围注意,有nm个点和2nm条边。注意剪枝

    如果有起点,终点的约束,起点d[]距离就赋值为0,其余赋值为无穷。而对于没有起点,终点的约束,全部d[]距离都赋值为无穷。spfa算法,把所有点一开始都入队,这样每个点都遍历到了,就能保证不会有负环由于图的不连通而不被找到。差分约束能把所有约束条件转换成边求最短路,判断负环来解决问题。

    #include <cmath>
    #include <queue>
    #include <cstdio>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    using namespace std;
    
    const int N=400+10;
    int n,m,cnt;
    const double INF=1e12;
    double l,r,c[N][N],d[N*2];
    int head[N*2],Time[N*2];
    bool vis[N*2];
    
    struct e{
        int to,next;
        double w;
    }edge[N*N*2]; // 有反向边
    
    void add(int u,int v,double w){
        edge[cnt].w=w;edge[cnt].to=v;edge[cnt].next=head[u];head[u]=cnt++;
    }
    
    void init(){
        cnt=0;
        memset(Time,0,sizeof(Time));
        memset(head,-1,sizeof(head));
    }
    
    bool SPFA(int s)
    {
        for(int i=0;i<2*N;i++) d[i]=INF;
        memset(vis,0, sizeof(vis));
        queue<int> q;
        q.push(s);
        d[s]=0;
        vis[s]=1;
        Time[s]=1;
        while(q.size())
        {
            int u = q.front();q.pop();
            vis[u]=0;
            for(int i=head[u];i!=-1;i=edge[i].next)
            {
                int v=edge[i].to;
                double w=edge[i].w;
                if(d[v]>d[u]+w)
                {
                    d[v]=d[u]+w;
                    if(!vis[v])
                    {
                        q.push(v);
                        vis[v]=1;
                        if(++Time[v]>sqrt(n+m))return false;
                    }
                }
            }
        }
        return true;
    }
    
    
    int main(){
        while(scanf("%d%d%lf%lf",&n,&m,&l,&r)!=EOF){
            init();
            for(int i=1;i<=n;i++)
                for(int j=1;j<=m;j++)
                {
                    scanf("%lf",&c[i][j]);
                    add(j+n,i,log(r/c[i][j]));
                    add(i,j+n,log(c[i][j]/l));
                }
            if(SPFA(1)) cout<<"YES"<<endl; // 从连通的顶点开始
            else cout<<"NO"<<endl;
        }
        return 0;
    }
  • 相关阅读:
    诡异的楼梯 HDU1180
    selenium的那些命令:
    权限管理:
    图片裁剪:
    2-15 showapiRequest解决图片验证码识别.py
    2-14 使用pytesseract识别图片中得问题.py
    使用C#开发ActiveX控件 11
    Mybatis+mysql动态分页查询数据案例——测试类HouseDaoMybatisImplTest)
    Mybatis+mysql动态分页查询数据案例——测试类HouseDaoMybatisImplTest)
    Mybatis+mysql动态分页查询数据案例——测试类HouseDaoMybatisImplTest)
  • 原文地址:https://www.cnblogs.com/demian/p/9205498.html
Copyright © 2011-2022 走看看