来源:2019 年“浪潮杯”第十届山东省 ACM 省赛
题意:
对于一个包含n个数的(n为奇数)序列val[ ],排序后的 val[ (n+1) / 2 ] 定义为 median;
有 n 个数,并有 m 组关系,对于第 i 组关系 ai,bi 代表第 val[ai] > val[bi];
但并没有给出具体的数值;
输出一个包含 n 个元素的数组 s[ ] ;
让你判断第 i 个数 val[ i ]是可能为中位数,如果是,第 i 位为 1;
如果不是,第 i 位为 0;
输出 n 个数,其中第 i 个数为 0 或 1,含义如上;
题解:
首先,特判两种情况:
①ai = bi;
②给出的 m 个关系有环;
对于这两种情况,输出 n 个 0;
除了这两种情况外,就是一个有向无环图;
如何判断第 i 位是否为 median 呢?
搜索:
正向搜索比第 i 个数小的数的总个数 tot1;
反向搜索比第 i 个数大的数的总个数 tot2;
那么,还剩下 res = n-(tot1+tot2+1) 个数;
如果 res ≥ |tot1-tot2|,那么第 i 个数就是中位数;
AC代码:
1 #include<bits/stdc++.h> 2 using namespace std; 3 #define mem(a,b) memset(a,b,sizeof(a)) 4 const int maxn=1e4+50; 5 6 int n,m; 7 int num; 8 int head[maxn]; 9 bool vis[150]; 10 bool isCir; 11 char s[200]; 12 struct Edge 13 { 14 int to; 15 int next; 16 }G[maxn<<1]; 17 void addEdge(int u,int v) 18 { 19 G[num]={v,head[u]}; 20 head[u]=num++; 21 } 22 struct SCC 23 { 24 vector<int >vs; 25 void DFS(int u) 26 { 27 vis[u]=true; 28 for(int i=head[u];~i;i=G[i].next) 29 { 30 int v=G[i].to; 31 if((i&1) || vis[v]) 32 continue; 33 DFS(v); 34 } 35 vs.push_back(u); 36 } 37 void RDFS(int u,int k) 38 { 39 vis[u]=true; 40 for(int i=head[u];~i;i=G[i].next) 41 { 42 int v=G[i].to; 43 if(!(i&1) || vis[v]) 44 continue; 45 RDFS(v,k); 46 } 47 } 48 int scc() 49 { 50 vs.clear(); 51 mem(vis,false); 52 for(int i=1;i <= n;++i) 53 if(!vis[i]) 54 DFS(i); 55 56 int k=0; 57 mem(vis,false); 58 for(int i=vs.size()-1;i >= 0;--i) 59 if(!vis[vs[i]]) 60 RDFS(vs[i],++k); 61 return k; 62 } 63 }_scc; 64 int DFS(int u)///正向搜索比第 i 个数小的数 65 { 66 int ans=1; 67 vis[u]=true; 68 for(int i=head[u];~i;i=G[i].next) 69 { 70 int v=G[i].to; 71 if((i&1) || vis[v]) 72 continue; 73 ans += DFS(v); 74 } 75 return ans; 76 } 77 int RDFS(int u)///反向搜索比第 i 个数大的数 78 { 79 int ans=1; 80 vis[u]=true; 81 for(int i=head[u];~i;i=G[i].next) 82 { 83 int v=G[i].to; 84 if(!(i&1) || vis[v]) 85 continue; 86 ans += RDFS(v); 87 } 88 return ans; 89 } 90 bool isSat(int u) 91 { 92 mem(vis,false); 93 int tot1=DFS(u)-1; 94 mem(vis,false); 95 int tot2=RDFS(u)-1; 96 97 return abs(tot1-tot2) <= (n-tot1-tot2-1) ? true:false; 98 } 99 char *Solve() 100 { 101 mem(s,'0'); 102 s[n]='\0'; 103 int k=_scc.scc();///强连通分量分解判断是否含有环 104 if(k < n) 105 isCir=true; 106 if(isCir) 107 return s; 108 109 for(int i=1;i <= n;++i) 110 if(isSat(i))///判断第 i 个数是否为median 111 s[i-1]='1'; 112 return s; 113 } 114 void Init() 115 { 116 num=0; 117 mem(head,-1); 118 isCir=false; 119 } 120 int main() 121 { 122 // freopen("C:\\Users\\hyacinthLJP\\Desktop\\in&&out\\contest","r",stdin); 123 int test; 124 scanf("%d",&test); 125 while(test--) 126 { 127 scanf("%d%d",&n,&m); 128 Init(); 129 for(int i=1;i <= m;++i) 130 { 131 int u,v; 132 scanf("%d%d",&u,&v); 133 if(u == v) 134 isCir=true; 135 addEdge(u,v);///正向边 136 addEdge(v,u);///反向边 137 } 138 printf("%s\n",Solve()); 139 } 140 return 0; 141 }