题目大意
有个圆,均匀分布 100 个点。编号从 1 到 100。
给你 n n n 组数对,一组数对 a , b a,b a,b 代表 a a a 与 b b b 之间有一条连线。
你要保留尽可能多的连线,使得他们互不相交。
解
区间DP。
设 a n s [ i ] [ j ] ans[i][j] ans[i][j] 为 i i i 到 j j j 的弧间,最多可以保留的连线。
那么 a n s [ i ] [ j ] = m a x ( a n s [ i ] [ k ] + a n s [ k ] [ j ] ) + l [ i ] [ j ] ans[i][j] = max(ans[i][k]+ans[k][j]) + l[i][j] ans[i][j]=max(ans[i][k]+ans[k][j])+l[i][j]
( k k k 是 弧 i j ij ij 上的点, l l l 为 i − j i-j i−j 间是否有连线)
然后我处理了 i − j i-j i−j 距离小于等于 50 50 50 的情况,再将两个半圆合并,得出最终结果。
代码
#include<cstdio>
#include<iostream>
#include<cmath>
using namespace std;
int n,a,b,l[120][120], e, le,ld, ans[120][120], anss;
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", &a, &b);
l[a][b] = l[b][a] = 1;
}
for(int i = 2; i <= 51; ++i) //长度
for(int q = 1; q <= 100; ++q){
//起始点
e = q+i-1; le = (e-1)%100+1; //终点
for(int d = q; d <= e; ++d){
//分割点
ld = (d-1)%100+1; //(这里前面带l的都是实际位置,不带的都是未经处理的
ans[q][le] = ans[le][q] = max(ans[le][q], ans[q][ld]+ans[ld][le]);
}
ans[q][le] += l[q][le];
anss = max(anss, ans[q][le]);
}
for(int i = 1; i <= 50; ++i) //枚举是哪俩半圆最终合并
anss = max(anss,
ans[i][i+49]+ans[i+50][(i+99-1)%100+1] //两半圆内连线数
+l[i][(i+99-1)%100+1]+l[i+49][i+50] //两半圆之间连线
+max(l[i][i+50], l[i+49][(i+99-1)%100+1])); //两半圆之间连线交叉的话取1
printf("%d", anss);
fclose(stdin);
fclose(stdout);
}