题目链接
题目思路
这个题目就是等价于正着建一次边,反着建一次边,然后看第\(i\)个点在这两种情况中能到达的点都小于\(\frac{n}{2}\)
则为\(1\),否则则为\(1\)
拓扑排序上\(dp\)是对于链的一些情况来考虑
这里需要floyd传递闭包来写这个
代码
#include<bits/stdc++.h>
#define fi first
#define se second
#define debug cout<<"I AM HERE"<<endl;
using namespace std;
typedef long long ll;
const int maxn=1e2+5,inf=0x3f3f3f3f;
const double eps=1e-6;
int n,m;
int u[maxn*maxn],v[maxn*maxn];
int sz[maxn][2];
bitset<maxn> b[maxn];
void cal(int id){
for(int mid=1;mid<=n;mid++){
for(int beg=1;beg<=n;beg++){
if(b[beg][mid]){
b[beg]|=b[mid];
}
}
}
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
sz[i][id]+=b[i][j];
}
}
}
signed main(){
int _;scanf("%d",&_);
while(_--){
memset(sz,0,sizeof(sz));
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++){
b[i].reset();
}
for(int i=1;i<=m;i++){
scanf("%d%d",&u[i],&v[i]);
b[u[i]][v[i]]=1;
}
cal(0);
bool flag=1;
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
if(b[i][j]&&b[j][i]) flag=0;
}
}
if(!flag){
for(int i=1;i<=n;i++){
printf("0");
}
printf("\n");
continue;
}
for(int i=1;i<=n;i++){
b[i].reset();
}
for(int i=1;i<=m;i++){
b[v[i]][u[i]]=1;
}
cal(1);
for(int i=1;i<=n;i++){
printf("%d",max(sz[i][0],sz[i][1])<=n/2);
}
printf("\n");
}
return 0;
}