POJ 3553 拓扑

POJ 3553
假设同一时刻t有两个活动i,j可做,
先做i  s1 =max(t+pi-di,t+pi+pj-dj,0)
先做j  s2 =max(t+pj-dj,t+pi+pj-di,0)
//此处省不省略0对证明不影响只对s1,s2影响。
//举例来说,省略0是超时完成要扣钱,提前完成有奖金
//而不省略0是是超时完成要扣钱,提前完成没有事件发生
1) s1中 t+pi-di>t+pi+pj-dj
   s2中 t+pj-dj>t+pi+pj-di
   有0>pi+pj,显而不符
2)s1中 t+pi-di>t+pi+pj-dj,即-di>pj-dj   ,可推出di<dj-pj<dj
   s2中 t+pj-dj<=t+pi+pj-di 
   s2-s1=pj,显然s1<=s2
3)s1中 t+pi-di<=t+pi+pj-dj,
   s2中 t+pj-dj>t+pi+pj-di 即-dj>pi-di ,推出dj<di-pi<di
   s2-s1=-pj,显然s2<=s1
4) s1中 t+pi-di<t+pi+pj-dj
   s2中 t+pj-dj<t+pi+pj-di
   s2-s1=dj-di,结果与(2)(3)相符
因此,假设同一时刻t有两个活动i,j可做,应优先做d值小的(与p无关)


拓扑5W个点,还要用上优先队列。

#include<string.h>
#include<stdio.h>
#define N 50005
#define M 500005
struct edge{
    int to,next;
}e[M];
int ru[N],head[N],tr[N],d[N],heap[N],fheap[N];
int o,n,m,size;
void swap(int *a,int *b)
{   int swap;
    swap=*a;*a=*b;*b=swap;
}
int min(int a,int b)
{   return a>b?b:a;
}
void up(int i)
{   while (i>1)
    {   if (d[heap[i]]<d[heap[i>>1]])
            {swap(fheap+heap[i>>1],fheap+heap[i]);
             swap(heap+(i>>1),heap+i);
            }
        else break;
        i>>=1;
    }
}
void down(int i)
{   while (i<<1<=size)
    {i<<=1;
     if (i<size&&d[heap[i+1]]<d[heap[i]]) i++;
     if (d[heap[i]]<d[heap[i>>1]]) {swap(fheap+heap[i>>1],fheap+heap[i]);
                                    swap(heap+(i>>1),heap+i);
                                 }
     else break;
    }
}
void add(int x,int y)
{   ru[y]++;
    e[o].to=y;
    e[o].next=head[x];
    head[x]=o++;
}
void topu()
{   int sum=0,i,j,yiip;
    size=0;
    for (i=1;i<=n;i++)
        if (ru[i]==0)
            { heap[++size]=i;
              fheap[i]=size;
              up(size);
            }
    while (sum<n)
        {   i=heap[1];
            tr[sum]=i;
 	    for (int k=head[i];k!=-1;k=e[k].next)
                {ru[e[k].to]--;
                 if (ru[e[k].to]==0) {heap[++size]=e[k].to;
                                      fheap[e[k].to]=size;
                                      up(size);
                                     }
                }

            sum++;
            yiip=fheap[i];
            fheap[heap[size]]=yiip;
            heap[yiip]=heap[size];
            size--;
            down(yiip);

        }
    for (i=0;i<n;i++)
        printf("%d\n",tr[i]);
}
void doit()
{   int i,j,x,y;
    memset(ru,0,sizeof(ru));
    memset(head,255,sizeof(head)); o=0;
    for (i=1;i<=n;i++)
        scanf("%d%d",&d[i],&d[i]);
    scanf("%d",&m);
    for (i=1;i<=m;i++)
        {scanf("%d%d",&x,&y);
         add(x,y);
        }
    topu();
}
int main()
{   while (scanf("%d",&n)!=EOF) doit();
    return 0;
}


  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值