題目連結:https://vjudge.net/contest/228455#problem/A
題目大意:
有2n個城市,其中有n個富有的城市,n個貧窮的城市,其中富有的城市只在一種資源富有,且富有的城市之間富有的資源都不相同,貧窮的城市只有一種資源貧窮,且各不相同,現在給出一部分貧窮城市的需求,每個需求都是一個貧窮的向一個富有的城市要資源,且每個富有的城市都想向貧窮的城市輸入自己富有的那部分資源,現在為了運輸要建設多條路,但是路與路之間不允許有交叉,求滿足貧窮城市的各種要求最多可以建設多少條路。
解題分析:
此題的難點在於很難看出求城市之間連線的最大值實際上就是,將a城市看成陣列,每一個a城市對應的b城市看成a陣列的對應值,然後就是求出a城市陣列的最長上升子序列的長度。因為要使城市之間的連線不交叉的數量最多,很明顯就是要求斜向一個同方向的線條(線條方向分為兩種,斜向左和斜向右)最多,即求a陣列的最長上升子序列。
記住了最長上升子序列如果要求嚴格上升的話就是lower_bound 可以相等的話就是upper_bound
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
int arr[]; int n;
int Lis[];
int cas = ;
void LIS() //求最大遞增子序列
{
//int Lis[500010]; //這個這麼大的陣列不能定義在子函式裡,否則會執行不了,無語
int len = ;
memset(Lis, , sizeof(Lis));
for (int i = ; i <= n; i++)
{
if (arr[i] > Lis[len])Lis[++len] = arr[i];
else
{
int j = lower_bound(Lis + , Lis + len + , arr[i]) - Lis;
Lis[j] = arr[i];
}
}
printf("Case %d:\n", ++cas);
if(len==)printf("My king, at most %d road can be built.\n\n",len); //哇,這裡好坑啊,原來只有一條路的時候road用單數,多條路用複數
else
printf("My king, at most %d roads can be built.\n\n", len);
} int main()
{
while (~scanf("%d", &n))
{
memset(arr, , sizeof(arr));
int a, b;
for (int i = ; i <= n; i++) {
scanf("%d %d", &a, &b);
arr[a] = b; //將城市之間的連線形象的轉變成,將b看成a城市的值,然後就將這道題轉變為了簡單的LIS
}
LIS();
}
return ;
}
2018-05-17