• poj 3275 "Ranking the Cows"(DFS or Floyd+bitset<>)


    传送门

    题意:

      农场主 FJ 有 n 头奶牛,现在给你 m 对关系(x,y)表示奶牛x的产奶速率高于奶牛y;

      FJ 想按照奶牛的产奶速率由高到低排列这些奶牛,但是这 m 对关系可能不能精确确定这 n 头奶牛的关系;

      问最少需要额外增加多少对关系使得可以确定这 n 头奶牛的顺序;

    题解:

      之所以做这道题,是因为在补CF的题时用到了bitset<>;

      搜这个容器的用法是看到了一篇标题为POJ-3275:奶牛排序Ranking the Cows(Floyd、bitset)的文章;

      正好拿着道题练练bitset<>;

      但是一做,发现,这道题和省赛的L题好像啊,做法完全相同,只是在输出结果上处理了一下;

      下午在补一下如何用bitset<>做这道题,先贴上DFS暴力AC代码;

    AC代码:

     1 #include<iostream>
     2 #include<cstdio>
     3 #include<cstring>
     4 using namespace std;
     5 #define mem(a,b) memset(a,b,sizeof(a))
     6 const int maxn=1e3+50;
     7 
     8 int n,m;
     9 int num;
    10 int head[maxn];
    11 struct Edge
    12 {
    13     int to;
    14     int next;
    15 }G[maxn*10*2];
    16 void addEdge(int u,int v)
    17 {
    18     G[num]={v,head[u]};
    19     head[u]=num++;
    20 }
    21 bool vis[maxn];
    22 
    23 int DFS(int u)
    24 {
    25     int ans=1;
    26     vis[u]=true;
    27     for(int i=head[u];~i;i=G[i].next)
    28     {
    29         int v=G[i].to;
    30         if(vis[v] || (i&1))
    31             continue;
    32         ans += DFS(v);
    33     }
    34     return ans;
    35 }
    36 int RDFS(int u)
    37 {
    38     int ans=1;
    39     vis[u]=true;
    40     for(int i=head[u];~i;i=G[i].next)
    41     {
    42         int v=G[i].to;
    43         if(vis[v] || !(i&1))
    44             continue;
    45         ans += RDFS(v);
    46     }
    47     return ans;
    48 }
    49 int Solve()
    50 {
    51     int ans=0;
    52     for(int i=1;i <= n;++i)
    53     {
    54         mem(vis,false);
    55         int t1=DFS(i);
    56         mem(vis,false);
    57         int t2=RDFS(i);
    58         ///第i头奶牛可以确定的奶牛个数为t1+t2-1
    59         ans += n-(t1+t2-1);
    60     }
    61     return ans>>1;
    62 }
    63 void Init()
    64 {
    65     num=0;
    66     mem(head,-1);
    67 }
    68 int main()
    69 {
    70     while(~scanf("%d%d",&n,&m))
    71     {
    72         Init();
    73         for(int i=1;i <= m;++i)
    74         {
    75             int u,v;
    76             scanf("%d%d",&u,&v);
    77             addEdge(u,v);
    78             addEdge(v,u);
    79         }
    80         printf("%d
    ",Solve());
    81     }
    82     return 0;
    83 }
    View Code

    思路2:(来自上述链接文章)

      确定这 n 头奶牛的顺序需要 n*(n-1)/2 对关系;

      (X,Y)代表 rankX > rankY

      已知关系 (X,Y),(Y,Z),那么,根据传递性可得隐藏关系(X,Z);

      如何根据给出的m条关系找到所有的隐藏关系呢?

      Floyd传递闭包;

    AC代码1:

     1 #include<iostream>
     2 #include<cstdio>
     3 #include<vector>
     4 #include<cstring>
     5 using namespace std;
     6 #define mem(a,b) memset(a,b,sizeof(a))
     7 const int maxn=1e3+50;
     8 
     9 int n,m;
    10 bool e[maxn][maxn];
    11 vector<int >in[maxn],out[maxn];
    12 ///in[u]:指向u的节点,out[u]:u指出去的节点
    13 
    14 int Solve()
    15 {
    16     int ans=0;
    17     for(int k=1;k <= n;++k)
    18     {
    19         for(int i=0;i < in[k].size();++i)
    20         {
    21             for(int j=0;j < out[k].size();++j)
    22             {
    23                 int u=in[k][i];
    24                 int v=out[k][j];
    25                 if(!e[u][v])///隐藏关系u->v
    26                 {
    27                     e[u][v]=true;
    28                     out[u].push_back(v);
    29                     in[v].push_back(u);
    30                     ans++;
    31                 }
    32             }
    33         }
    34     }
    35     ///m:已知关系对
    36     ///ans:隐藏关系对
    37     return n*(n-1)/2-m-ans;
    38 }
    39 int main()
    40 {
    41     scanf("%d%d",&n,&m);
    42     for(int i=1;i <= m;++i)
    43     {
    44         int u,v;
    45         scanf("%d%d",&u,&v);
    46         in[v].push_back(u);
    47         out[u].push_back(v);
    48         e[u][v]=true;
    49     }
    50     printf("%d
    ",Solve());
    51 
    52     return 0;
    53 }
    View Code

    另一种写法就是用到了bitset<>容器;

    bitset<1001>_bit[1001];
    对于输入的关系<u,v>;
    _bit[u].set(v);//将第v为置位1,表示有一条u->v的边

    如何找到所有的隐藏关系呢?

    for(int i=1;i <= n;++i)
        for(int j=1;j <= n;++j)
            if(_bit[j][i])
                _bit[j] |= _bit[i];///让j节点指向i节点所有指出去的边

    晚上一直困惑,为什么将if()及其之后的语句改为

    if(_bit[i][j])
        _bit[i] |= _bit[j];

    就wa了,找了许久,终于找到了;

    对于如下关系:

    (①,③) , (③,②) , (②,④)

    (①->③->②->④)

    当 i = 1 时,如果按照更改后的写法,①只会更新出<①,②>而不会更新出关系<①,④>(纸上画一下就出来了);

    所以说,要更新内层循环的节点,这样更新的彻底;

    AC代码2:

     1 #include<iostream>
     2 #include<cstdio>
     3 #include<vector>
     4 #include<cstring>
     5 #include<bitset>
     6 using namespace std;
     7 #define mem(a,b) memset(a,b,sizeof(a))
     8 const int maxn=1e3+50;
     9 
    10 int n,m;
    11 bitset<maxn>_bit[maxn];
    12 
    13 int Solve()
    14 {
    15     for(int i=1;i <= n;++i)
    16         for(int j=1;j <= n;++j)
    17             if(_bit[j][i])
    18                 _bit[j] |= _bit[i];///让j节点指向i节点所有指出去的边
    19 
    20     int ans=0;
    21     for(int i=1;i <= n;++i)
    22         ans += _bit[i].count();
    23 
    24     ///ans:m对已有关系对+隐藏关系对
    25     return n*(n-1)/2-ans;
    26 }
    27 int main()
    28 {
    29     scanf("%d%d",&n,&m);
    30     for(int i=1;i <= m;++i)
    31     {
    32         int u,v;
    33         scanf("%d%d",&u,&v);
    34         _bit[u].set(v);
    35     }
    36     printf("%d
    ",Solve());
    37 
    38     return 0;
    39 }
    View Code
  • 相关阅读:
    emacs写cnblog博客
    emacs写cnblog博客
    linux安装jdk
    linux远程服务器启动mysql时显示:/tmp/mysql.sock 不存在的解决方法
    最新Linux系统下安装MySql 5.7.17全过程及注意事项
    Xshell实现Windows上传文件到Linux主机
    4种java定时器
    微信的redirect_uri参数错误解决办法
    要善于借势破局——宁向东的清华管理学课第4课
    Java内存区域
  • 原文地址:https://www.cnblogs.com/violet-acmer/p/10898098.html
Copyright © 2020-2023  润新知