码迷,mamicode.com
首页 > 其他好文 > 详细

POJ 1364 / HDU 3666 【差分约束-SPFA】

时间:2018-06-20 21:13:01      阅读:164      评论:0      收藏:0      [点我收藏+]

标签:size   oid   ++   min   pac   sqrt   []   xmlns   ram   

 

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\n");
70         else printf("successful conspiracy\n");
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】

标签:size   oid   ++   min   pac   sqrt   []   xmlns   ram   

原文地址:https://www.cnblogs.com/demian/p/9205498.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!