题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1025
题目大意:有两行按编号升序排列的城市,相对的城市希望彼此修筑道路,且互相修路的配对是事先安排好的,要求所修的道路两两不相交,问最多能修多少条道路?
分析题意:
1、显然,可以根据配对,先将一边的(poorcities)城市按从小到大的顺序排列,按次顺序,然后求另一边的城市(rich cities)编号的最长递增序列。
2、第一种方法:很自然想到动态规划,很简单,不多解释。
3、第二种方法:实际上可以利用堆栈实现。保持栈中的元素按照升序排列,每次新加入的元素与栈顶元素比较,大于栈顶元素,直接进栈,否则替换栈中第一个大于该元素的元素,需用二分查找,降低时间复杂度。(意思实际上是减小栈的潜在增加的可能性)
#include<stdio.h>
#include<malloc.h>
#define MAX 500001
int stack[MAX];
int top = 0;
void push(int e){
stack[++top] = e;
}
void exchange(int e){
int low, high, middle;
low = 1;
high = top;
while(low<=high){
middle = (low+high)/2;
if(stack[middle]<e){
low = middle+1;
}
else if(stack[middle]>e){
high = middle-1;
}
else{
return;
}
}
stack[low] = e;
}
void clearStack(){
top = 0;
}
int LIS2(int *a, int n){
int temp;
int i;
clearStack();
push(a[1]);
for(i=2; i<= n; i++){
temp = a[i];
if(stack[top]<temp){
push(temp);
}
else{
exchange(temp);
}
}
return top;
}
int main(){
int *a, p;
int n, i;
int caseNum, res;
caseNum = 1;
while(scanf("%d", &n)!=EOF){
a = (int*)malloc(sizeof(int)*(n+1));
for(i=0; i<n; i++){
scanf("%d", &p);
scanf("%d", &a[p]);
}
res = LIS2(a, n);
printf("Case %d:\n", caseNum);
if(res > 1){
printf("My king, at most %d roads can be built.\n\n", res);
}
else{
printf("My king, at most %d road can be built.\n\n", res);
}
free(a);
caseNum++;
}
return 0;
}