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\n",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("\n"); 57 } 58 return 0; 59 }
把每一件简单的事情做好,就是不简单;把每一件平凡的事情做好,就是不平凡!相信自己,创造奇迹~~