前言
我考试时敲了一个不仅比正解编程复杂度高,而且时间更慢,还AC不了的费用流
垃圾代码
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
#define MN 20011
using namespace std;
struct node{
int to,w,next,c;
}a[150001];
queue<int> q;
int tot,k,n,c,s,e,x,y,w,sum;
int ls[MN],maxf[MN],b[MN],f[MN],v[MN];
void addl(int x,int y,int w,int c)
{
a[++tot].to=y;a[tot].w=w;
a[tot].next=ls[x];ls[x]=tot;
a[tot].c=c;
a[++tot].to=x;a[tot].w=0;
a[tot].next=ls[y];ls[y]=tot;
a[tot].c=-c;
}
bool spfa()
{
memset(f,-127/3,sizeof(f));
while (!q.empty()) q.pop();
q.push(s);v[s]=true;f[s]=0;maxf[s]=2147483647;
while (!q.empty())
{
int x=q.front();
v[x]=false;
q.pop();
for (int i=ls[x];i;i=a[i].next)
{
int y=a[i].to;
if (a[i].w&&f[x]+a[i].c>f[y])
{
f[y]=f[x]+a[i].c;
maxf[y]=min(maxf[x],a[i].w);
b[y]=i;
if (!v[y])
{
q.push(y);
v[y]=true;
}
}
}
}
if (f[e]>-690563370) return true;
else return false;
}
int updata()
{
x=e;
int ans=0;
while (x!=s)
{
a[b[x]].w-=maxf[e];
a[b[x]^1].w+=maxf[e];
ans+=a[b[x]].c;
x=a[b[x]^1].to;
}
return ans*maxf[e];
}
int main()
{
tot=1;
scanf("%d%d%d",&k,&n,&c);
s=n+1;e=s+1;
addl(s,1,c,0);addl(n,e,c,0);
for (int i=1;i<n;i++) addl(i,i+1,c,0);
for (int i=1;i<=k;i++)
{
scanf("%d%d%d",&x,&y,&w);
addl(x,y,w,1);
}
while (spfa())
sum+=updata();
printf("%d",sum);
}
//If you want to AK(IOI)!
//first:
// AK | AK IOI
//sto orz|sto orz
//sto orz|sto orz
//sto xjq orz|sto hzb orz
//sto orz|sto orz
//sto orz|sto orz
//Then you will AK(IOI)!
//不要问我为啥会有上面的东西
大意
一个列车可以坐 C C 头牛,有组牛,每组 mi m i 个,从 si s i 出发到 ei e i 。求最多可以带多少头牛。
解题思路
首先众所周知可以用数学归纳法证明每次选取结束时间最早的是最优解
自己理解的证明:
选结束时间晚的只有两种情况
1.
![]()
这种情况绿色比红色占的范围更大,肯定不一定最优解。
2.
![]()
这种情况由于被红色线段占了的已经计算过了,如果计算红色的话那么前面的一定没有被红色覆盖,所以按照这么算其实就是这样
![]()
这样的话绿色占的范围依旧比红色大,所以依旧不一定是最优解。
好了,证明完了之后就可以先按照结束位置排个序,用 (i,i) ( i , i ) 这个区间来表示在 i i <script type="math/tex" id="MathJax-Element-238">i</script>这个时间点车子计算到现在空闲的容量,然后枚举将每个开始到结束区间尽量减到0(能减就减,当然注意这个组的人数)
代码
#include<cstdio>
#include<algorithm>
using namespace std;
struct node{
int star,end,w;
}w[50001];
struct treenode{
int l,r,w,lazy;
}a[80001];
int k,n,c,s;
void build(int x,int l,int r,int num)
{
a[x].l=l;a[x].r=r;a[x].w=num;
if (l==r) return;
int mid=(l+r)/2;
build(x*2,l,mid,num);
build(x*2+1,mid+1,r,num);
}
void ddata(int x)
{
if (a[x].lazy)
{
a[x*2].w+=a[x].lazy;
a[x*2+1].w+=a[x].lazy;
a[x*2].lazy+=a[x].lazy;
a[x*2+1].lazy+=a[x].lazy;
a[x].lazy=0;
}
}
void updata(int x,int l,int r,int num)
{
if (a[x].l==l&&a[x].r==r)
{
a[x].w+=num;
a[x].lazy+=num;
return;
}
ddata(x);
if (a[x*2].r>=r) updata(x*2,l,r,num);
else if (a[x*2+1].l<=l) updata(x*2+1,l,r,num);
else updata(x*2,l,a[x*2].r,num),updata(x*2+1,a[x*2+1].l,r,num);
a[x].w=min(a[x*2].w,a[x*2+1].w);
}
int find(int x,int l,int r)
{
if (a[x].l==l&&a[x].r==r)return a[x].w;
ddata(x);
if (a[x*2].r>=r) return find(x*2,l,r);
else if (a[x*2+1].l<=l) return find(x*2+1,l,r);
else
{
a[x].w=min(a[x*2].w,a[x*2+1].w);
return min(find(x*2,l,a[x*2].r),find(x*2+1,a[x*2+1].l,r));
}
}
bool cmp(node x,node y)
{
return x.end<y.end;
}
int main()
{
scanf("%d%d%d",&k,&n,&c);
for (int i=1;i<=k;i++)
{
scanf("%d%d%d",&w[i].star,&w[i].end,&w[i].w);
}
build(1,1,n,c);//建树
sort(w+1,w+1+k,cmp);//排序
for (int i=1;i<=k;i++)
{
int h=find(1,w[i].star,w[i].end-1);
if (h)//是否可以接牛
{
updata(1,w[i].star,w[i].end-1,-min(h,w[i].w));//修改区间
s+=min(h,w[i].w);//累计答案
}
}
printf("%d",s);
}