ZOJ 1076 Gene Assembly(LIS+路径打印 贪心)

题目链接:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=76

题目大意:在一个DNA上,给定许多基因的起始位置和结束位置,求出这条链上最多同时存在多少基因?并依次输出选择基因的序列号。

Sample Input

6
340 500
220 470
100 300
880 943
525 556
612 776
3
705 773
124 337
453 665
0

Sample Output

3 1 5 6 4
2 3 1

分析:有两种思路。1.最长上升子序列+路径打印;2.贪心

法1:

 1 //dp[i] = max{0,dp[j]}+1,j<i
 2 //时间复杂度仍为 O(n^2)
 3 //
 4 
 5 # include<stdio.h>
 6 # include<string.h>
 7 # include<stdlib.h>
 8 # define MAX 1001
 9 
10 struct node{
11     int x,y,id;    //x,y分别是基因起始和结束位置,id表示基因的序列号
12 }data[MAX];
13 
14 int n;
15 int pre[MAX];    //记录前驱
16 int dp[MAX];    //LIS中保存最大数目
17 int output[MAX];    //记录输出
18 
19 int cmp(const void *a,const void *b){    //将序列从小到大排序
20     struct node *c = (node *)a;
21     struct node *d = (node *)b;
22     if(c->x == d->x)
23         return c->y - d->y;
24     return c->x - d->x;
25 }
26 
27 void solve(){
28     int i,j,m;
29     qsort(data,n,sizeof(data[0]),cmp);
30     pre[0] = -1;
31     dp[0] =1;
32     for(i=1;i<n;i++){
33         pre[i] = -1;
34         dp[i] = 1;
35         m = 0;
36         for(j=0;j<i;j++){
37             if(data[j].y < data[i].x){
38                 if(m<dp[j]){
39                     m = dp[j];        //LIS
40                     pre[i] = j;
41                 }
42             }
43         }
44         dp[i] += m ;
45     }
46     j = m = 0;
47     for(i=0;i<n;i++){    //找到最长的序列的最后一个
48         if(dp[i] > m){
49             j = i;
50             m = dp[i];
51         }
52     }
53     i = 0;
54     while(j != -1){
55         output[i++] = j;
56         j = pre[j];
57     }
58     for(j=i-1; j>0; j--)
59         printf("%d ",data[output[j]].id);
60     printf("%d
",data[output[j]].id);
61 }
62 int main(){
63     while(scanf("%d",&n) && n){      
64         for(int i=0;i<n;i++){
65             scanf("%d%d",&data[i].x,&data[i].y);
66             data[i].id = i+1;
67         }
68         solve();
69     }
70     return 0;
71 }

法2:

 1 /*可以将基因起始点看成一个作业的开始时间,基因终点看成完成该作业的终止时间。用这些基因拼出长度最长的基因序列(连续的基因前一个终点不能大于等于后一个基因起始点),相当于求能完成的最多作业序列。这是贪心的典型例题。可用贪心算法解决,贪心策略——优先考虑先完成的作业。*/
 2 #include <stdio.h>
 3 #include <string.h>
 4 
 5 int input[1001][3];    //input[i][0]:起始位置,input[i][1]:终止位置,input[i][2]:编号
 6 
 7 int main( )
 8 {
 9     int N, i, j, k;
10     int temp, max;
11     /*输入基因个数N,N=0时测试结束*/
12     while( scanf( "%d", &N ) )
13     {
14         if( N==0 )  break;    //输入结束
15         memset( input, 0, sizeof(input) );
16         /*输入基因起始点,终止点,并给基因编号*/
17         for( i=0; i<N; i++ )
18         {
19             scanf( "%d%d", &input[i][0], &input[i][1] );
20             input[i][2] = i + 1;
21         }
22         /*对基因按终止点小的排序,<1000的用例,选择排序法*/ 
23         for( i=0; i<N; i++ )
24         {
25             temp = input[i][1];
26             k = i;
27             for( j = i + 1; j<N; j++ )
28             {
29                 if( temp>input[j][1] )
30                 {
31                     k = j;
32                     temp = input[j][1]; 
33                 }
34             }
35             temp = input[i][0];
36             input[i][0] = input[k][0];
37             input[k][0] = temp;
38             temp = input[i][1];
39             input[i][1] = input[k][1];
40             input[k][1] = temp;
41             temp = input[i][2];
42             input[i][2] = input[k][2];
43             input[k][2] = temp;
44         }
45         /*贪心选择输出被选择的基因编号*/
46         max = input[0][1];
47         printf( "%d", input[0][2] );
48         for( i=1; i<N; i++ )
49         {
50             if( input[i][0]>max )
51             {
52                 printf( " %d", input[i][2] );
53                 max = input[i][1];
54             }
55         }   
56         printf("
");
57     }
58     return 0;
59 }
原文地址:https://www.cnblogs.com/acm-bingzi/p/3234696.html