类似二取方格数 , 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; }