• poj1275收银员——差分约束


    题目:http://poj.org/problem?id=1275

    做的第一道差分约束题...

    首先,根据题意得出一些不等关系(f为前缀和雇佣人数):

    0 <= f[i] - f[i-1] <= t[i];      // 雇佣的人数少于申请者但不能为负数
    f[i] - f[i-8] >= r[i]              // 当x>=8时,该方程成立,否则将出现负数显然不成立
    f[i-8+24] - f[i] <= x - r[i]   // 当x<8时,由于昨天的雇人可以通宵上班,因此这个约束通过反面处理
    f[24] - f[0] >= x              // 最后24小时内雇佣人应该大于等于x个人

    其中x是一个需要二分的变量,也就是最终雇佣了多少人;

    而最后一个条件,可以看做是强制选x个人,那么即使实际上雇佣了小于x的人,spfa结果仍为(-)x,这样可以来判断x是否为可行解;

    千辛万苦终于AC,最后迟迟难A的问题竟然是spfa中没有给vis数组赋0!这是习惯错误,因为这个spfa与平常不同的是有中途return 0,所以可能没有把vis全赋会0就退出,所以每次需要重新赋0。

    代码如下:

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<queue>
    using namespace std;
    queue<int>q;
    int const MAXN=40;
    int T,n,r[MAXN],t[MAXN],ct,head[MAXN],L,R,dis[MAXN],cnt[MAXN];
    bool vis[MAXN];
    struct N{
        int to,next,w;
        N(int t=0,int n=0,int w=0):to(t),next(n),w(w) {}
    }edge[MAXN*70];
    bool spfa(int x)
    {
        while(q.size())q.pop();
        memset(dis,0x3f,sizeof dis);
        memset(cnt,0,sizeof cnt);
        memset(vis,0,sizeof vis);//!!!
        int s=24;
        q.push(s);vis[s]=1;dis[s]=0;cnt[s]=1;
        //根据加边看到应该从后往前走,从-x人出发,dis为负 
        while(q.size())
        {
            int x=q.front();q.pop();vis[x]=0;
            if(cnt[x]>25)return 0;//若入队>25次,可判断存在负环 
            for(int i=head[x];i;i=edge[i].next)
            {
                int u=edge[i].to;
                if(dis[u]>dis[x]+edge[i].w)
                {
                    dis[u]=dis[x]+edge[i].w;
                    if(!vis[u])vis[u]=1,q.push(u),cnt[u]++;
                }
            }
        }
        return dis[0]==-x;//是否的确雇佣了x个人(没有被边限制卡掉) 
    }
    bool pd(int x)
    {
        ct=0;
        memset(head,0,sizeof head);
        for(int i=1;i<8;i++)
        {
            edge[++ct]=N(i+24-8,head[i],x-r[i]);head[i]=ct;
            edge[++ct]=N(i,head[i-1],t[i]);head[i-1]=ct;
            edge[++ct]=N(i-1,head[i],0);head[i]=ct;
        
        }
        for(int i=8;i<=24;i++)
        {
            edge[++ct]=N(i-8,head[i],-r[i]);head[i]=ct;
            edge[++ct]=N(i,head[i-1],t[i]);head[i-1]=ct;
            edge[++ct]=N(i-1,head[i],0);head[i]=ct;
        }
        edge[++ct]=N(0,head[24],-x);head[24]=ct;//!f[24]-f[0]>=x
        return spfa(x);
    }
    int main()
    {
        scanf("%d",&T);
        while(T--)
        {
            for(int i=1;i<=24;i++)
                scanf("%d",&r[i]);
            scanf("%d",&n);
            for(int i=1;i<=n;i++)
            {
                int x;
                scanf("%d",&x);
                t[x+1]++;//从1~24计算 
            }
            L=0;R=n;
            int ans=-1;
            while(L<=R)
            {
                int mid=((L+R)>>1);
                if(pd(mid))ans=mid,R=mid-1;
                else L=mid+1;
            }
            if(ans!=-1)printf("%d
    ",ans);
            else printf("No Solution
    ");
        }
        return 0;
    }
  • 相关阅读:
    理解inode
    贝叶斯公式与拼写检查器
    《C程序设计语言》第四章 函数和程序结构
    MIT《计算机科学与编程导论》课堂笔记
    很牛的牛顿迭代法
    开发一个小工具重温C#经典问题
    斯坦福《编程方法学》环境搭建及常见问题
    看Sybase官方手册学索引工作原理
    学习编程的方法、软件和工具
    大师里奇留给了我们什么
  • 原文地址:https://www.cnblogs.com/Zinn/p/8871324.html
Copyright © 2020-2023  润新知