差分约束系统专题

1、教程
书籍:算法导论p370、黑书
论文:http://wenku.baidu.com/view/c37d3486bceb19e8b8f6baae.html
博客:http://www.cnblogs.com/wangyaohui/articles/2134040.html
http://www.cppblog.com/mythit/archive/2009/06/04/86756.html
http://www.cnblogs.com/litstrong/archive/2010/08/08/1795268.html
(先这些,找到好的再换)
2、一些题目
hdu:1384 1529 1531 1534 3440 3592 3666

poj:1201 1275 1364 2983 3159 3169 
3、解题报告

http://972169909-qq-com.iteye.com/blog/1185527

http://blog.csdn.net/l04205613/article/details/6660930
poj1201 & hdu1384
先定义s[i+1]表示0-i中选的个数,于是
1、题意:[ai,bi]中至少ci个可以表示为s[bi+1]-s[ai]>=ci 
2、定义:1>=s[i+1]-s[i]>=0,也就是i选与不选两种情况
最终s[max+1]-s[min]即为所求

差分约束系统有求最长路,最短路两种方式
1、最长路:s[bi+1]-s[ai]>=ci
2、最短路:s[ai]-s[bi+1]<=-ci

hdu 1529 & poj1275
x[i] 表示第i时刻选定的人数
n[i] 表示第i时刻可选的人数
r[i] 表示第i时刻需要的人数

x[i] <= n[i]
x[i]+x[i-1]+...+x[i-7] >= r[i]

令s[i]=x[0]+x[1]+...+x[i]

0<=s[i]-s[i-1]<=n[i], i=1,2..23
s[0]<=n[0]
s[i]-s[i-8]>=r[i], i=8,9..23
s[23]+s[i]-s[i+16]>=r[i], i=0,1..7

整理得
s[i]-s[i-1]>=0, i=1,2..23
s[i-1]-s[i]>=-n[i], i=1,2..23
s[0]>=-n[0]
s[i]-s[i-8]>=r[i] , i=8,9..23
s[i]-s[i+16]>=r[i]-s[23], i=0,1..7

求min(s[23])

 

代码1:

#include<cstdio>
#include<cstring>
#include<climits>
#include<iostream>
#include<queue>
#include<vector>

using namespace std;

#define min(a,b) a<b?a:b
#define max(a,b) a>b?a:b

const int N = 51000;
struct node{ int v, x; };
vector<node> edg[N];
int vis[N], tim[N], dis[N];
queue<int> q;
int s, t, o, n;

void input()
{
    node tmp;
    int u, v, x;

    for(x=0; x<N; ++x) edg[x].clear();

    s=INT_MAX; t=INT_MIN;
    // add input edge
    while(n--)
    {
        scanf("%d%d%d", &u, &v, &x);
        s=min(s, u); t=max(t, v);
        tmp.v=v+1; tmp.x=x;
        edg[u].push_back(tmp);
    }
    t++;
    // add -1 edge
    for(u=t; u>s; --u)
    {
        tmp.v=u-1; tmp.x=-1;
        edg[u].push_back(tmp);
    }
    // add 0 edge
    for(u=s; u<t; ++u)
    {
        tmp.v=u+1; tmp.x=0;
        edg[u].push_back(tmp);
    }
}

void spfa()
{
    int i, u, v, x, m;

    memset(vis, 0, sizeof(vis));
    for(i=s; i<=t; ++i) dis[i]=-INT_MAX;
    while(!q.empty()) q.pop();

    dis[s]=0; q.push(s); vis[s]=1;
    while(!q.empty())
    {
        u=q.front(); q.pop(); vis[u]=0;
        m=edg[u].size();
        for(i=0; i<m; ++i)
        {
            v=edg[u][i].v;
            x=edg[u][i].x;
            if(dis[v]<dis[u]+x)
            {
                dis[v]=dis[u]+x;
                if(!vis[v])
                {
                    vis[v]=1; q.push(v);
                }
            }
        }
    }
    printf("%d\n", dis[t]-dis[s]);
}

int main()
{
    while(~scanf("%d",&n))
    {
        input();
        spfa();
    }
    return 0;
}


代码2:

#include<cstdio>
#include<cstring>
#include<climits>
#include<iostream>
#include<queue>
#include<vector>

using namespace std;

#define min(a,b) a<b?a:b
#define max(a,b) a>b?a:b

const int N = 51000;
struct node{ int v, x; };
vector<node> edg[N];
int vis[N], tim[N], dis[N];
queue<int> q;
int s, t, o, n;

void input()
{
    node tmp;
    int u, v, x;

    for(x=0; x<N; ++x) edg[x].clear();

    s=INT_MAX; t=INT_MIN;
    // add input edge
    while(n--)
    {
        scanf("%d%d%d", &v, &u, &x);
        u++; s=min(s, v); t=max(t, u);
        tmp.v=v; tmp.x=-x;
        edg[u].push_back(tmp);
    }
    // add 0 edge
    for(u=t; u>s; --u)
    {
        tmp.v=u-1; tmp.x=0;
        edg[u].push_back(tmp);
    }
    // add 1 edge
    for(u=s; u<t; ++u)
    {
        tmp.v=u+1; tmp.x=1;
        edg[u].push_back(tmp);
    }
    u=o=t+1; tmp.x=0;
    // add o-> x
    for(x=s; x<=t; ++x)
    {
        tmp.v=x; edg[u].push_back(tmp);
    }
    n=t-s+2;
}

void spfa()
{
    int i, u, v, x, m;

    memset(vis, 0, sizeof(vis));
    memset(tim, 0, sizeof(tim));
    for(i=s; i<=t; ++i) dis[i]=INT_MAX;
    while(!q.empty()) q.pop();

    dis[o]=0; q.push(o); vis[o]=tim[o]=1;
    while(!q.empty())
    {
        u=q.front(); q.pop(); vis[u]=0;
        m=edg[u].size();
        for(i=0; i<m; ++i)
        {
            v=edg[u][i].v;
            x=edg[u][i].x;
            if(dis[v]>dis[u]+x)
            {
                dis[v]=dis[u]+x;
                if(!vis[v])
                {
                    vis[v]=1; q.push(v); tim[v]++; 
                    if(tim[v]>n) 
                        while(!q.empty()) q.pop();
                }
            }
        }
    }
    printf("%d\n", dis[t]-dis[s]);
}

int main()
{
    while(~scanf("%d",&n))
    {
        input();
        spfa();
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值