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\n",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\n",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\n",Solve());
37 
38     return 0;
39 }
View Code

 

posted @ 2019-05-21 10:00  HHHyacinth  阅读(174)  评论(0编辑  收藏  举报