poj 2983 差分约束学习(用队列超时了,不防用栈试试)

对于差分约束,写了两道题,有了自己的想法,归纳为3点

1,找出所有条件,其中包括隐含的。

2,对所有条件进行分析,转化为3角不等式。

3,应用最短路,或最长路,进行松弛操作,或判环

  差分约束题目有两种,一种求最大值,另外一种求最小值。

       (1)当题目是求满足给定不等式的最小值时,就是求图的最长路。

        建图方式如下:a – b >= c,对应于边b –> a w(b, a) = c, 然后求最短路;判断条件是:d[v] <= d[u] + w(u, v), 初始化d[]为-INF. 这样求出的d[]就是满足条件的最小值。原因很简单,因为d[i] 是从-INF开始增大,根据不等式逐渐增大,当满足所有不等式时,那么d[i]肯定是最小的了。

       (2)当题目是求满足给定不等式的最大值时,就是求图的最短路。

        建图方式如下:a – b <= c,对应于边b –> a w(b, a) = c, 然后求最长路;判断条件是:d[v] >= d[u] + w(u, v), 初始化d[]为INF.这样求出的d[]就是最大值。原因和上面一样,因为是从INF逐渐减小的,当满足完所有条件时,就停止。那么d[i]是最大的了。


推荐:spfa算法

#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>
using namespace std;
const int M =  100008;
int top = 0;
struct {
    int head;
}H[M];
struct {
    int u,v,w,next;
}E[M*10];
void add(int u,int v,int w)
{
    E[top].v = v;
    E[top].w = w;
    E[top].next = H[u].head;
    H[u].head = top++;
}
void init()
{
    top = 0;
    memset(H,-1,sizeof(H));
    memset(E,-1,sizeof(E));
}
bool spfa(int f,int n)
{
    int d[M],vis[M],_cnt[M];
    memset(d,63,sizeof(d));
    d[f] = 0;
    memset(vis,0,sizeof(vis));
    memset(_cnt,0,sizeof(_cnt));
    queue <int > q ;
    q.push(f);
    vis[f] = 1;
    _cnt[f]++;
    while(!q.empty())
    {
        int u = q.front();q.pop(),vis[u] = 0;
        for(int i = H[u].head;i!=-1;i = E[i].next)
        {

            if(d[E[i].v]>d[u]+E[i].w)
            {
                d[E[i].v] = d[u] + E[i].w;
                if(!vis[E[i].v])
                {
                    q.push(E[i].v);
                    vis[E[i].v] = 1;
                    _cnt[E[i].v] ++;
                    if(_cnt[E[i].v]>n)return false;
                }
            }
        }
    }
    return true;
}
int main()
{
    int m,n;
    while(~scanf("%d%d",&n,&m))
    {
        init();
        char a[10];
        int u,v,w;
        while(m--)
        {
            scanf("%s",a);
            if(a[0]=='P')
            {
                scanf("%d%d%d",&u,&v,&w);
                add(u,v,-w);
                add(v,u,w);
            }
            else
            {
                scanf("%d%d",&u,&v);
                add(u,v,-1);
            }
        }
         for(int i=1;i<=n;i++)add(0,i,0);
         spfa(0,n)==true?puts("Reliable"):puts("Unreliable");

    }
}


评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值