摆渡线路
题目链接:SSL 2877 / SSL 1964 / SSL 1599
题目大意
有一个圆,均匀分布 100 个点从 1 到 100。
然后两个点之间可能会有线段。
然后要你保留尽可能多的线段,使得保留的线段互不相交。
思路
这道题看到环,先把它弄成链。
然后你就会发现其实就是要你选的线段在链上不会有重叠而且不是全部重叠的部分。
那你可以考虑用 dp 来解决。
就枚举中间中转的地方,把一个大的区间分成两个小的区间。
然后如果你大区间左右端点间有线,那这条线是一定可以选的。
那你可以用这样的方法,设 f i , j f_{i,j} fi,j 为 i i i 到 j j j 最多可以选多少条线。
f i , j = max i ≤ k ≤ j { f i , k + f k , j } + a i , j f_{i,j}=\max\limits_{i\leq k \leq j}\{f_{i,k}+f_{k,j}\}+a_{i,j} fi,j=i≤k≤jmax{
fi,k+fk,j}+ai,j
a i , j a_{i,j} ai,j 是两点间是否有线段。
然后你最后找到 f i , i + 100 f_{i,i+100} fi,i+100 中最大的那个输出即可。
代码
#include<cstdio>
#include<iostream>
#include<algorithm>
using namespace std;
int n, x, y, f[201][201], ans, a[201][201];
int main() {
// freopen("line.in", "r", stdin);
// freopen("line.out", "w", stdout);
scanf("%d", &n);
for (int i = 1; i <= n; i++) {
scanf("%d %d", &x, &y);
if (x > y) swap(x, y);
a[x][y] = 1;
a[x + 100][y + 100] = 1;//把环弄成链
}
for (int dis = 1; dis <= 100; dis++)//区间dp
for (int i = 1; i + dis - 1 <= 200; i++) {
int j = i + dis - 1;
for (int k = i; k <= j; k++)
f[i][j] = max(f[i][j], f[i][k] + f[k][j]);
f[i][j] += a[i][j];
}
for (int i = 1; i <= 100; i++)
ans = max(ans, f[i][i + 100 - 1]);
printf("%d", ans);
fclose(stdin);
fclose(stdout);
return 0;
}