P1315,jzoj3029-观光公交【费用流】

版权声明:原创,未经作者允许禁止转载 https://blog.csdn.net/Mr_wuyongcong/article/details/86541082

前言

你绝对想不到,我用费用流神仙构图做了一道
图.jpg
的题


正题

评测记录:https://www.luogu.org/recordnew/lists?uid=52918&pid=P1315


题目大意

n n 个地方, i i 到第 i + 1 i+1 的长度为 d i d_i
m m 个人,从 t i t_i 出发,从 l i l_i r i r_i
k k 个氮气,可以让一条路变短。
求所有人等待时间之和


解题思路

我们考虑费用流。
对于每个点,无论车来多早都要等最后一个人,我们记录这个人到达时间为 l a s t i last_i
对于每个点,我们计算出在没有加速的情况下,到达这个点的时间为 g e t i get_i
对于每个点,我们计算出下车的人数 d o w n i down_i
对于每个点,如果到达的出发的早一点,就有可能可以影响到下一个点。

这样如果不用加速所有人等待时间之和为
i = 1 m g e t r i t i \sum_{i=1}^mget_{r_i}-t_i
我们可以用费用流求加速可以加多少时间。

我们开始构图,对于每个图,我们用流量表示氮气。
S S 拆一个 S S' ,然后 S > S S->S' 容量 k k ,代价0
对于第 i i 个点,我们拆一个 i i' i i 表示普通点, i i' 表示影响点。
我们让 S > i S'->i ,容量 d i d_i ,代价0。表示只能用 d i d_i 个氮气加速
我们让 i > i + 1 i'->i+1 ,容量 i n f inf ,代价0。表示这边的点可以影响到下一个点。
我们让 i > T i->T ,容量 i n f inf ,代价0。让已经不能再起作用的氮气走。
我们让 i > i i->i' ,容量 m a x { g e t i l a s t i , 0 } max\{get_i-last_i,0\} ,代价 d o w n i + 1 down_{i+1} 表示只有那么多个氮气可以影响到下一个点,且影响到所有后面下车的人。


c o d e code

#include<cstdio>
#include<cstring>
#include<algorithm>
#define N 8010
#define M 10010
#define inf 0x3f3f3f3f
using namespace std;
struct line{
    int to,w,c,next;
}a[N];
struct node{
	int t,l,r;
}peo[M];
int sd,s,t,d[N],down[N],last[N],get[N],k;
int tot,n,m,f[N],ls[N],tail,answer;
int state[N],x,y,w,c,ans,head,pre[N];
bool v[N];
void addl(int x,int y,int w,int c)
{
    a[++tot].to=y;a[tot].w=w;a[tot].c=c;
    a[tot].next=ls[x];ls[x]=tot;
    a[++tot].to=x;a[tot].w=0;a[tot].c=-c;
    a[tot].next=ls[y];ls[y]=tot;
}
bool spfa()
{
    memset(f,0x3f,sizeof(f));
    memset(v,0,sizeof(v));
    head=0;tail=1;v[s]=true;
    state[1]=s;f[s]=0;
    while (head!=tail)
    {
        head=head%N+1;
        int x=state[head];
        for (int q=ls[x];q;q=a[q].next)
        {
            int y=a[q].to;
            if (a[q].w&&f[x]+a[q].c<f[y])
            {
                f[y]=f[x]+a[q].c;
                pre[y]=q;
                if (!v[y])
                {
                    v[y]=true;
                    tail=tail%N+1;
                    state[tail]=y;
                }
            }
        }
        v[x]=false;
    }
    if (f[t]>=707406378) return 0;
    else return 1;
}
void upway()
{
    int k=2147483647,now=t;
    while (now!=s)
    {
        k=min(k,a[pre[now]].w);
        now=a[pre[now]^1].to;
    }
    ans+=f[t]*k;now=t;
    answer+=k;
    while (now!=s)
    {
        a[pre[now]].w-=k;
        a[pre[now]^1].w+=k;
        now=a[pre[now]^1].to;
    }
}
int main()
{
	freopen("data.in","r",stdin);
	//freopen("data.out","w",stdout);
	tot=1;
	scanf("%d%d%d",&n,&m,&k);
	s=n*2+1,sd=n*2+2,t=n*2+3;
	for(int i=1;i<n;i++)
	  scanf("%d",&d[i]);
	for(int i=1;i<=m;i++){
		scanf("%d%d%d",&peo[i].t,&peo[i].l,&peo[i].r);
		down[peo[i].r]++;last[peo[i].l]=max(last[peo[i].l],peo[i].t);
	}
	for(int i=1;i<n;i++)
	  get[i+1]=max(get[i],last[i])+d[i];
	for(int i=1;i<=m;i++)
	  ans+=get[peo[i].r]-peo[i].t;
	addl(s,sd,k,0);
	for(int i=1;i<n;i++)
	{
		addl(i,i+n,max(get[i]-last[i],0),0);
		addl(i+n,i+1,inf,-down[i+1]);
		addl(sd,i+n,d[i],0);
		addl(i+1,t,inf,0);
	}
    while (spfa())
      upway();
	printf("%d",ans);
}

猜你喜欢

转载自blog.csdn.net/Mr_wuyongcong/article/details/86541082