传送门

来源: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 }
View Code

相关文章: