题意
给出一些点,及其大小关系,找出哪些点可以通过重排,排在中间。
链接:link。
思路
命题:假设严格比节点
i
i
i小的节点数为
L
L
L,比节点
i
i
i大的节点数为
R
R
R,如果
L
≤
n
2
L\leq \frac{n}{2}
L≤2n且
R
≤
n
2
R\leq \frac{n}{2}
R≤2n,那么可以通过重排,将
i
i
i排在中间。
证明:略。
根据大小关系建立一个图 g [ i ] [ j ] g[i][j] g[i][j],然后利用Floyd算法测试任意两个节点的连通性(如果 g [ i ] [ j ] = 1 g[i][j]=1 g[i][j]=1,那么 p o i n t [ i ] < p o i n t [ j ] point[i]<point[j] point[i]<point[j]),最后求出 L L L和 R R R。
时间复杂度分析
时间复杂度主要取决于Floyd算法,时间复杂度为 O ( n 3 ) \mathcal{O}(n^{3}) O(n3)。
实现
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int N=1e2+10;
int g[N][N],l[N],r[N];
int main(){
int T;scanf("%d",&T);
while(T--){
int n,m;scanf("%d %d",&n,&m);
memset(g,0,sizeof(g));
memset(l,0,sizeof(l));
memset(r,0,sizeof(r));
for(int i=1;i<=m;i++){
int x,y;scanf("%d %d",&x,&y);
g[x][y]=1;
}
for(int k=1;k<=n;k++){
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
if(g[i][k]&&g[k][j]){
g[i][j]=1;
}
}
}
}
int flag=0;
for(int i=1;i<=n;i++){
if(g[i][i]) flag=1;
for(int j=1;j<=n;j++){
if(g[j][i]) l[i]+=g[j][i];
if(g[i][j]) r[i]+=g[i][j];
}
}
if(flag){
for(int i=1;i<=n;i++) printf("0");
printf("\n");
continue;
}else{
for(int i=1;i<=n;i++){
if(l[i]<=n>>1&&r[i]<=n>>1) printf("1");
else printf("0");
}
printf("\n");
}
}
return 0;
}