题意:
现在有n*2个点围成一个圈,告诉你有m对点已经相连。让你自由让剩下n*2=m*2个点两两相连,每个点最多被用到一次。问你最后这些线段最多有多少交点(不用管点的间距)。
题解:
这种题目我还不太会做…
首先考虑n*2个点围成的圈,假设没有已经相连该怎么做最大。
一开始连一条边,然后连第二条边的时候与第一条有一个交点,连第三条的时候与前两条都有交点…以此类推。
那么我们就知道是前n个点一次跟后n个点相连,就像这样:
1连n,2连n+1,3连n+2…
但是现在有已经相连的情况。这个时候怎么连是最大的,也就是较短间隔的所有可使用的点连得边都与他有交点,或许是这样:
那么对于蓝色的已经固定的线来说,这样就是与它交点最大的一种情况。
那么我们可以发现,前面所描述的前n个点与后n个点依次相连的方法可以让较少的部分的所有可使用的点都与它有交点。那么最终答案就是如此。
计算交点的时候,正常来说如果数据范围是1e5,那么就需要使用树状数组这种数据结构维护差分数组来做,但是它只有100的数据范围,因此直接
n
2
n^2
n2来找答案即可。
C++代码:
#include<bits/stdc++.h>
using namespace std;
#define pii pair<int,int>
const int N=205;
vector<pii>vec;
int vis[N];
int main()
{
int t;
scanf("%d",&t);
while(t--){
vec.clear();
memset(vis,0,sizeof(vis));
int n,m;
scanf("%d%d",&n,&m);
int ans=0;
for(int i=1;i<=m;i++){
int x,y;
scanf("%d%d",&x,&y);
vis[x]=vis[y]=1;
vec.push_back({min(x,y),max(x,y)});
}
int res=n-m,sta=1;
while(res){
if(!vis[sta])res--;
sta++;
}
for(int i=1;sta<=n*2;i++){
if(vis[i])continue;
while(vis[sta])sta++;
if(sta>n*2)break;
vec.push_back({i,sta});
sta++;
}
for(int i=0;i<vec.size();i++){
for(int j=i+1;j<vec.size();j++){
int x1=vec[i].first,y1=vec[i].second,x2=vec[j].first,y2=vec[j].second;
if(y1>y2)swap(x1,x2),swap(y1,y2);
if(x2>x1&&x2<y1)ans++;
}
}
printf("%d\n",ans);
}
return 0;
}
Python代码:
t=int(input())
while t>0:
t=t-1
n,m=map(int,input().split(' '))
ans=0
vec=[]
vis=[0]*205
for i in range(1,m+1):
x,y=map(int,input().split(' '))
vec.append([min(x,y),max(x,y)])
vis[x]=vis[y]=1
res=n-m;sta=1
while res>0:
if vis[sta]==0:
res=res-1
sta=sta+1
for i in range(1,n*2+1):
if vis[i]==1:continue
while vis[sta]==1 :sta+=1
if sta>n*2:break
vec.append([i,sta])
sta=sta+1
l= len(vec)
for i in range(l):
for j in range(i+1,l):
x1=vec[i][0];y1=vec[i][1];x2=vec[j][0];y2=vec[j][1]
if y1>y2 :x1,x2=x2,x1;y1,y2=y2,y1
if (x2>x1)and(x2<y1):ans=ans+1
print(ans)