POJ 1364 / HDU 3666 差分约束-SPFA

Posted demian

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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;
}

 

以上是关于POJ 1364 / HDU 3666 差分约束-SPFA的主要内容,如果未能解决你的问题,请参考以下文章

POJ 1364[差分约束]

差分约束POJ1364/LG UVA515 king

HDU3666 THE MATRIX PROBLEM (差分约束+取对数去系数)(对退出情况存疑)

hdu3592(差分约束) (线性)

Candies---hdu3159(spfa+差分约束)

POJ 1384 Intervals (线性差分约束,根据不等式建图,然后跑spfa)