zoukankan      html  css  js  c++  java
  • zoj 4124 "Median" (思维?假的图论?)

    传送门

    来源: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]='';
    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
    ",Solve());
    139     }
    140     return 0;
    141 }
    View Code

    凯少思路:

    如果 tot1 ≤ n/2 && tot2 ≤ n/2 返回 true;

    在返回结果的时候改成这句也可以,我的判断方法也对;

    代码:

      1 #include <iostream>
      2 #include <vector>
      3 #include <cstring>
      4 #include <queue>
      5 #include <cstdio>
      6 #include <algorithm>
      7 #include <cmath>
      8 #include <stack>
      9 using namespace std;
     10 const int ss = 200;
     11 int v1[ss];
     12 int v2[ss];
     13 int dfn[ss];
     14 int low[ss];
     15 int vis[ss];
     16 int son1[ss];
     17 int son2[ss];
     18 int pot[ss];
     19 vector < int >G[ss];
     20 vector < int >P[ss];
     21 stack < int >S;
     22 int scc, tim, n, m, t;
     23 void start()
     24 {
     25     memset(v1, 0, sizeof(v1));
     26     memset(v2, 0, sizeof(v2));
     27     memset(dfn, 0, sizeof(dfn));
     28     memset(vis, 0, sizeof(vis));
     29     memset(low, 0, sizeof(low));
     30     memset(pot, 0, sizeof(pot));
     31     memset(son1, 0, sizeof(son1));
     32     memset(son2, 0, sizeof(son2));
     33     for (int i = 1; i <= n; i++)
     34     {
     35         G[i].clear();
     36         P[i].clear();
     37     }
     38     while (!S.empty())
     39         S.pop();
     40     scc = tim = n = m = 0;
     41 }
     42 void tar(int u)
     43 {
     44     int v;
     45     low[u] = dfn[u] = ++tim;
     46     S.push(u);
     47     vis[u] = 1;
     48     for (int i = 0; i < G[u].size(); i++)
     49     {
     50         v = G[u][i];
     51         if (!dfn[v])
     52         {
     53             tar(v);
     54             if (low[u] > low[v])
     55                 low[u] = low[v];
     56         } else if (vis[v] && low[u] > dfn[v])
     57             low[u] = dfn[v];
     58     }
     59     if (low[u] == dfn[u])
     60     {
     61         scc++;
     62         do
     63         {
     64             v = S.top();
     65             S.pop();
     66             vis[v] = 0;
     67         } while (v != u);
     68     }
     69 }
     70 int dfs1(int x)
     71 {
     72     v1[x] = 1;
     73     for (int i = 0; i < G[x].size(); i++)
     74     {
     75         if (!v1[G[x][i]])
     76             son1[x] += dfs1(G[x][i]);
     77     }
     78     return son1[x] + 1;
     79 }
     80 int dfs2(int x)
     81 {
     82     v2[x] = 1;
     83     for (int i = 0; i < P[x].size(); i++)
     84     {
     85         if (!v2[P[x][i]])
     86             son2[x] += dfs2(P[x][i]);
     87     }
     88     return son2[x] + 1;
     89 }
     90 void print(int x, int p)
     91 {
     92     for (int i = 1; i <= n; i++)
     93     {
     94         if (i == p)
     95             printf("1");
     96         else
     97             printf("0");
     98     }
     99     printf("
    ");
    100 }
    101 int main()
    102 {
    103     cin >> t;
    104     while (t--)
    105     {
    106         start();
    107         int ok = 1;
    108         cin >> n >> m;
    109         for (int i = 1; i <= m; i++)
    110         {
    111             int a, b;
    112             scanf("%d%d", &a, &b);
    113             if (a == b)
    114                 ok = 0;
    115             G[a].push_back(b);
    116             P[b].push_back(a);
    117         }
    118         if (!ok)
    119         {
    120             print(n, 0);
    121         } else
    122         {
    123             for (int i = 1; i <= n; i++)
    124                 if (!dfn[i])
    125                     tar(i);
    126             if (scc != n)
    127                 print(n, 0);
    128             else
    129             {
    130                 int point = 0;
    131                 for (int i = 1; i <= n; i++)
    132                 {
    133                     dfs1(i);
    134                     dfs2(i);
    135                     if ((son1[i] <= (n / 2)) && (son2[i] <= (n / 2)))
    136                         pot[i] = 1;
    137                     memset(son1, 0, sizeof(son1));
    138                     memset(son2, 0, sizeof(son2));
    139                     memset(v1, 0, sizeof(v1));
    140                     memset(v2, 0, sizeof(v2));
    141                 }
    142                 for (int i = 1; i <= n; i++)
    143                     cout << pot[i];
    144                 cout << "
    ";
    145             }
    146         }
    147     }
    148     return 0;
    149 }
    View Code

    因为 n 很小,所以对每个点跑两次DFS并不会超时;

    但,如果 n 大了呢,那制定不能每个点跑两次DFS了,那该肿么办呢?

    本蒟蒻还没想出来~~~~~~~~

    据说,此题正解为求解两次拓扑序;

    https://paste.ubuntu.com/p/xXxYdnDRBV/

  • 相关阅读:
    一、列表
    正则表达式
    form表单学习
    HTTP场景应用
    fiddler几种功能强大的用法(二)
    在VMW里安装Ghost操作系统遇到的问题及解决的办法
    浮点数值的表示
    补码和补码的计算
    个人主页项目总结
    Todolist项目总结 JavaScript+jQuery
  • 原文地址:https://www.cnblogs.com/violet-acmer/p/10859207.html
Copyright © 2011-2022 走看看