类似二取方格数 , fj有2个房子出租,1000个order , 给出order的时间范围和pay,求如何安排能得到最大的收益
TLE的构图方式:以order为点,设一组源汇和一组超级源汇,对每个order拆点,权值为1 , 花费为-c ,没有时间冲突的order之间连边权值为1 , 花费为0 。
这种方法果断超时了,2000个点4000000条边。【50组数据跑6s多 , 标程0.125s】
膜拜了torry的代码之后的改进构图方法:以时间为点,相邻时间到时间都连边w=2 , c=0 ,order的边直接加在点间 , 但这里要处理下就是order的结束时间要+1 , 这样可以去点反身边 以及避免2个order有相同时间的冲突会同时选上的错误。
spfa的费用流还是很给力的
【torry 牛出题 ,当时标程数组开小了以为是数据错误。。。】
#include <cstdio>
#include <cstring>
#define min(a,b) (a>b?b:a)
#define max(a,b) (a<b?a:b)
using namespace std;
const int maxn=410;
const int inf=2000000000;
int n;
struct Edge{
int v,next,c,w;
}edge[3500];
int head[maxn],cnt;
void addedge(int u,int v,int w,int c)
{
edge[cnt].v=v;
edge[cnt].w=w;
edge[cnt].c=c;
edge[cnt].next=head[u];
head[u]=cnt++;
edge[cnt].v=u;
edge[cnt].w=0;
edge[cnt].c=-c;
edge[cnt].next=head[v];
head[v]=cnt++;
}
//for spfa and mcmf
int dis[maxn],pre[maxn];//最小费用和前驱结点
int alpha[maxn];//标记
int que[maxn],qhead,qrear;
int spfa (int s,int e)//源汇点
{
//寻找费用增广,没有返回-1;
for (int i=0 ; i<maxn ; ++i)
dis[i]=inf;
memset (alpha , 0 , sizeof(alpha));
dis[s]=0;
que[qhead=0]=s;
qrear=1;
alpha[s]=1;
while (qhead!=qrear)//头可能大于尾
{
int k=que[qhead++];
qhead%=maxn;//循环队列
alpha[k]=0;
for (int q=head[k] ; ~q ; q=edge[q].next)
if(edge[q].w)
if(dis[k]+edge[q].c<dis[edge[q].v])
{
dis[edge[q].v]=dis[k]+edge[q].c;
pre[edge[q].v]=q;
if(!alpha[edge[q].v])
{
alpha[edge[q].v]=true;
if(edge[q].c<0)
{
qhead=(qhead-1+maxn)%maxn;
que[qhead]=edge[q].v;
}
else
{
que[qrear++]=edge[q].v;
qrear%=maxn;
}
}
}
}
if(dis[e]==inf)return -1;
//终点不可达,返回-1;
int k=inf;
for(int i=e ; i!=s ; i=edge[pre[i]^1].v)
k=min(k,edge[pre[i]].w);
//sum+=k;//sum记录最大流(有些题里会用到)
return k;//返回该可行流流量
}
struct order {
int a,b,c;
}o[maxn];
int mcmf(int s,int t)
{
int ans=0,k;
while (~(k=spfa(s,t)))
{
//printf("!!!\n");
for (int i=t ; i!=s ; i=edge[pre[i]^1].v)
{
edge[pre[i]].w-=k;
edge[pre[i]^1].w+=k;
}//更新流
ans+=dis[t]*k;//最小费用*流量
}
return ans;
}
///以order为点的构图会超时,拆点后2000的点,2000*2000的边
/*
void build_graph()
{
cnt=0;
memset (head , -1 , sizeof(head));
addedge(0 , 1 , 2 , 0);
addedge(2*n+2 , 2*n+3 , 2 , 0);
for (int i=0 ; i<n ; ++i)
{
addedge(i+2 , i+2+n , 1 , -o[i].c);
addedge(1 , i+2 , 2 , 0);
addedge(i+2+n , 2*n+2 , 1 , 0);
for (int j=0 ; j<n ; ++j)
{
if(o[i].b<o[j].a)addedge(i+2+n , j+2 , 1 , 0);
}
}
}
*/
///以时间为点构图 , 400个点 , 1000条边 S=0 t=402
void build_graph()
{
cnt=0 ;
memset (head , -1 , sizeof(head));
for (int i=0 ; i<=401 ; ++i)
{
addedge(i , i+1 , 2 , 0);
}
for (int i=0 ; i<n ; ++i)
{
addedge(o[i].a+1 , o[i].b+2 , 1 , -o[i].c);
}
}
int main()
{
//freopen ("data.txt","r",stdin);
//freopen ("std.txt","w",stdout);
int cas;
scanf("%d",&cas);
while (cas--)
{
scanf("%d",&n);
for (int i=0 ; i<n ; ++i)
{
scanf("%d%d%d",&o[i].a , &o[i].b , &o[i].c);
}
build_graph();
int ans=mcmf(0 , 402);
printf("%d\n",-ans);
}
return 0;
}