LightOJ1360 Skyscraper(DP)

题目大概是,一个数轴上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\n",cse,d[mx]);
34     }
35     return 0;
36 }

 

你可能感兴趣的:(LightOJ1360 Skyscraper(DP))