AcWing
  • 首页
  • 课程
  • 题库
  • 更多
    • 竞赛
    • 题解
    • 分享
    • 问答
    • 应用
    • 校园
  • 关闭
    历史记录
    清除记录
    猜你想搜
    AcWing热点
  • App
  • 登录/注册

【题解】差分约束系统——POJ1275

作者: 作者的头像   RingweEH ,  2020-01-21 14:29:46 ,  所有人可见 ,  阅读 945


4


1

之前做过差分,但是没做过差分约束系统。
正好在学军机房听课讲到这道题,就顺带学了一下。
其实…就是列不等式组然后建图
作为蒟蒻,当然是不会加二分优化的啦…但是poj上还是94ms跑过了qwq
(其实是懒qwq)

解题分析放代码里了。

/*
算法:差分约束系统+二分
思路:设读入的人中,从i时刻开始的人数为num[i],雇佣的人数为x[i]。
    i时刻需要的人为r[i]
    据此,可以列出两个不等式:
    1. 0<=x[i]<=num[i]
    2.sum( x[j] )>=r[i] (j=i-7~i)
    很容易想到用前缀和。
    s[i]=sum( x[j] ),j=1~i
    1. s[i]-s[i-1]<=num[i]
    2.  s[i]-s[i-8]>=r[i]    8<=i<=24
        s[i]-s[i+16]+s[24]>=r[i]     1<=i<8
        (s[i]-s[i+16]>=r[i]-s[24])
    二分s[24],然后建图,根据差分约束系统.

    ps:差分约束系统中如果是>=,要么跑最长路,要么不等式两边同时*(-1)
*/

#include <iostream>
#include <queue>
using namespace std;
#define MAXN 25
#define inf 1<<20
struct node 
{
    int to,weight,next;
}a[MAXN*30];
int head[MAXN],dis[MAXN],cnt[MAXN]; 
int tot,n,r[MAXN],t[MAXN];
bool vis[MAXN]; 

void add( int u,int v,int w )       //邻接表
{
    a[tot].to=v; a[tot].weight=w; a[tot].next=head[u]; head[u]=tot++;
}

void mem()      //初始化
{
    tot=0;
    for ( int i=0; i<MAXN; i++ )
    {
        head[i]=-1; dis[i]=inf; vis[i]=0; cnt[i]=0;
    }
    dis[0]=0;
}

void build( int ans )       //根据差分关系建图
{
    mem();
    add( 0,24,-ans );
    for ( int i=1; i<MAXN; i++ )
    {
        add( i-1,i,0 ); add( i,i-1,t[i] );
    }
    for ( int j=1; j<MAXN; j++ )
    {
        int i=(j+8)%24;
        if ( i>j ) add( j,i,-r[i] );
        else add( j,i,-r[i]+ans );
    }
}

/*
  SPFA判断是否有解
  因为这个解只有两种情况,无解和有解,而只要不是无解,
  第一个找到的有解即为最优解,所以只要没有负环就可以return 1
  其实这里可以加二分优化(单调性,人总是越多越好),但是程序中采用了直接枚举,
  复杂度也是可以接受的。 
*/
bool check( int ans )  
{
    queue<int> q;
    q.push( 0 ); vis[0]=1; cnt[0]=1;
    while ( !q.empty() )
    {
        int p,t=q.front();
        q.pop(); p=head[t]; vis[t]=0;
        while ( p!=-1 )
        {
            if ( dis[a[p].to] > dis[t]+a[p].weight )
            {
                dis[a[p].to]=dis[t]+a[p].weight;
                if ( !vis[a[p].to] )
                {
                    vis[a[p].to]=1;
                    q.push( a[p].to );
                    cnt[a[p].to]++;
                    if ( cnt[a[p].to]>24 ) return 0;
                }
            }
            p=a[p].next;
        }
    }
    return 1;
}

int main()
{
    int T;
    scanf( "%d",&T );
    while ( T-- )
    {
        for ( int i=1; i<=24; i++ )
        {
            scanf( "%d",&r[i] ); t[i]=0;
        }
        scanf( "%d",&n );
        for ( int i=0; i<n; i++ )
        {
            int tmp; 
            scanf( "%d",&tmp ); t[tmp+1]++;
        }

        bool flag=1;
        for ( int i=0; i<=n; i++ )
        {
            build( i );
            if ( check(i) )
            {
                printf( "%d\n",i );
                flag=0; break;
            }
        }
        if ( flag ) printf( "No Solution\n" );
    }
}

update 2020.3.26
发现这道题lyd书里也有…… 393.雇佣收银员

8 评论


用户头像
cht   2020-05-08 15:27         踩      回复

tql

用户头像
RingweEH   2020-05-08 15:34         踩      回复

ORZ

用户头像
cht   2020-05-08 15:37    回复了 RingweEH 的评论         踩      回复

%%%%%%%%%%%%%%%%%%

用户头像
RingweEH   2020-05-08 15:38    回复了 cht 的评论         踩      回复

您也很巨QAQ

用户头像
cht   2020-05-08 15:39    回复了 RingweEH 的评论         踩      回复

我没有啊


用户头像
cht   2020-05-08 15:27         踩      回复

tql


用户头像
chinaxjh   2020-02-01 21:35         踩      回复

orz

用户头像
RingweEH   2020-05-08 15:37         踩      回复

STO


App 内打开
你确定删除吗?
1024
x

© 2018-2025 AcWing 版权所有  |  京ICP备2021015969号-2
用户协议  |  隐私政策  |  常见问题  |  联系我们
AcWing
请输入登录信息
更多登录方式: 微信图标 qq图标 qq图标
请输入绑定的邮箱地址
请输入注册信息