zoukankan      html  css  js  c++  java
  • ZOJ 4124 拓扑排序+思维dfs

    ZOJ - 4124 Median

      题目大意:有n个元素,给出m对a>b的关系,问哪个元素可能是第(n+1)/2个元素,可能的元素位置相应输出1,反之输出0

      省赛都过去两周了,现在才补这题,这题感觉不难,可能那时脑子混了,题意也没理解清楚。根据题目很容易看出,这跟拓扑排序有关,不过拓扑排序的作用在于判断给出的关系是否矛盾,在找判断可能是第(n+1)/2个元素还主要是思维。

      哪个元素可能是中间的(n+1)/2个元素呢,就是那些明确在它前面的元素(比它大的)的数目和在它后面的元素(比它小的)的数目都不大于(n-1)/2个的元素,因为剩下的不确定比它大还是比它小的元素可以任意补在它的前面或者后面。所以我们可以用个dfs来处理对任意节点来说明确在它前面的,还有后面的元素的数目。就对任意一个节点来说,比比它小的元素的还小的元素肯定是比它小的,所以具体操作就是,我们对每个元素x进行dfs,然后对每个可以推断出比它小的但没未标记的元素y都进行更新,也就是在x后面的元素++,然后y前面的元素++,最后标记x比y大。

      详情见代码,因为边也不多,所以我直接用了vector没用前向星。

     1 #include<cstdio>
     2 #include<vector>
     3 #include<queue>
     4 using namespace std;
     5 const int N=118;
     6 vector<int> vv[N];
     7 bool big[N][N];//big[i][j]就标记i是否比j大
     8 int du[N],vis[N],pre[N],back[N];
     9 void init(int n)
    10 {
    11     for(int i=0;i<=n;i++)
    12     {
    13         du[i]=0;
    14         vis[i]=0;
    15         pre[i]=back[i]=0;
    16         vv[i].clear();
    17         for(int j=0;j<=n;j++)
    18             big[i][j]=false;
    19     }
    20 }
    21 bool tp(int n)
    22 {
    23     queue<int> q;
    24     for(int i=1;i<=n;i++)
    25         if(du[i]<=0&&!vis[i])
    26         {
    27             vis[i]=1;
    28             q.push(i); 
    29         }
    30     int sum=0,x,y;
    31     while(!q.empty())
    32     {
    33         x=q.front();
    34         q.pop();
    35         sum++;
    36         for(int i=0;i<vv[x].size();i++)
    37         {
    38             y=vv[x][i];
    39             du[y]--;
    40             if(du[y]<=0&&!vis[y])
    41             {
    42                 vis[y]=1;
    43                 q.push(y); 
    44             }
    45         }
    46     }
    47     return sum==n;
    48 }
    49 void dfs(int u,int f)
    50 {
    51     for(int i=0;i<vv[u].size();i++)
    52     {
    53         int v=vv[u][i];
    54         if(!big[f][v])//f>v但还未标记,可以进行更新 
    55         {
    56             big[f][v]=true;
    57             pre[v]++;//在v前面的元素数目++ 
    58             back[f]++;//在f后面的元素数目-- 
    59             dfs(v,f);
    60         }
    61     }
    62 }
    63 int main()
    64 {
    65     int t,n,m,u,v;
    66     scanf("%d",&t);
    67     while(t--)
    68     {
    69         scanf("%d%d",&n,&m);
    70         init(n);
    71         while(m--)
    72         {
    73             scanf("%d%d",&u,&v);
    74             du[v]++;
    75             vv[u].push_back(v);
    76         }
    77         if(!tp(n))//拓扑排序判给出的关系是否矛盾 
    78         {
    79             for(int i=1;i<=n;i++)
    80                 putchar('0');
    81             puts("");
    82         }
    83         else
    84         {
    85             for(int i=1;i<=n;i++)
    86                 dfs(i,i);
    87             for(int i=1;i<=n;i++)
    88                 if(pre[i]<=(n-1)/2&&back[i]<=(n-1)/2)
    89                     putchar('1');
    90                 else
    91                     putchar('0');
    92             puts("");
    93         }
    94     }
    95     return 0;
    96 }
    一层一层拓扑你的心
  • 相关阅读:
    将font-size设置为 12px 以下,Chrome浏览器只能显示12px怎么办?
    如何创建.gitignore文件,忽略不必要提交的文件
    linux中将网速设置成10baseT/Half用于测试
    点击checkbox后满足条件才改变状态
    使用parted和kpartx 来对sdcard镜像进行分区调整,顺便用一下losetup
    linux添加具有root权限的管理员账号
    windows下获取系统的UUID
    pip修改镜像源
    linux中umount和mount
    mac安装brew
  • 原文地址:https://www.cnblogs.com/LMCC1108/p/10935292.html
Copyright © 2011-2022 走看看