题目大概是,一个数轴上n个线段,每个线段都有起始坐标、长度和权值,问从中取出没有公共交点的线段的最大权和。
取k次是个经典的最小费用最大流问题,不过这题建容量网络有20W个点,离散化最多也要6W个点,跑不动最小费用最大流的样子。。
其实这题也是个经典的DP,区间图最大权独立集问题,《挑战程序设计竞赛》有介绍。
- dp[i]表示坐标在[0,i]范围内能得到的最大的线段权值和
- dp[i]=max(dp[i-1],max(dp[j]+w)([j,i]是一条权w的线段))
用左闭右开的区间表示这道题的线段。用邻接表存一下各个坐标是哪几条线段的右端点,这样时间复杂度就是O(n+m),n为线段数,m为坐标最大值。
1 #include<cstdio> 2 #include<cstring> 3 #include<vector> 4 using namespace std; 5 struct Edge{ 6 int v,w,next; 7 }edge[33333]; 8 int NE,head[222222]; 9 void addEdge(int u,int v,int w){ 10 edge[NE].v=v; edge[NE].w=w; edge[NE].next=head[u]; 11 head[u]=NE++; 12 } 13 int d[222222]; 14 int main(){ 15 int t,n,a,b,c; 16 scanf("%d",&t); 17 for(int cse=1; cse<=t; ++cse){ 18 NE=0; 19 memset(head,-1,sizeof(head)); 20 scanf("%d",&n); 21 int mx=0; 22 while(n--){ 23 scanf("%d%d%d",&a,&b,&c); 24 addEdge(a+b,a,c); 25 mx=max(mx,a+b); 26 } 27 for(int i=1; i<=mx; ++i){ 28 d[i]=d[i-1]; 29 for(int j=head[i]; j!=-1; j=edge[j].next){ 30 d[i]=max(d[i],d[edge[j].v]+edge[j].w); 31 } 32 } 33 printf("Case %d: %d ",cse,d[mx]); 34 } 35 return 0; 36 }