• POJ 2942 Knights of the Round Table


    嘟嘟嘟

     

    这道题debug了两个下午终于AC了(还是对拍好用),心中十分激动~~

    首先不得不说,不看题解我是无论如何也想不出怎么建图的,刚开始直接按仇恨关系建图怎么搞也好不出来。

    题解说,要建互补图!就是如果两个骑士能挨一块,就连一条边。然后tarjan求点双联通分量。为什么求点双联通分量呢?因为每一个会议都要围成一个环,而一个人不能同时参加两个会议,所以对于两个点u, v,要有至少两条完全不同的路能从u到v,那就是求点双联通分量了。

    点双联通分量的求法和找割点很像,不过还有维护一个栈。如果这个节点第一次遍历,就放入栈中;如果low[v] >= dfn[u],说明u可能是割点(因为可能是根节点),但这并没有什么关系,这时候开始弹栈,直到st.top == v,因为u可能同时在多个点双中,所以u不能弹出,但还要把u加入这个点双中。记录所有点双,拿一个vector就行。

    然后题中说,每一个会议参加的人数必须是奇数,所以我们要在点双联通分量里找奇环。有一个结论:如果一个点双联通分量中存在一个奇环,那么联通分量中任意一个点都在奇环上。这个好证:

    假设奇环是x->B->y->A->x。然后对于两桶分量中的节点u:有两个环:u->x->B->y->u和u->x->A->y->u。又因为x->B->y和x->A->y中一定有一条路径是奇数的,那么包含u的两个环中一定有一个是奇环。

    那么如何找奇环呢?判断二分图时有这么个结论:如果一张图不存在奇环,那么就是二分图。做法就是黑白染色,如果u走到得一个节点v已经被染过色了,且col[u] == col[v],那么就存在奇环。

    然后如果这个联通分量中没有奇环,这些人就都无法参加任何一个会议。

    还有一件事,这道题拿邻接矩阵存图比较方便一些。

      1 #include<cstdio>
      2 #include<iostream>
      3 #include<cmath>
      4 #include<algorithm>
      5 #include<cstring>
      6 #include<cstdlib>
      7 #include<cctype>
      8 #include<vector>
      9 #include<stack>
     10 #include<queue>
     11 using namespace std;
     12 #define enter puts("") 
     13 #define space putchar(' ')
     14 #define Mem(a, x) memset(a, x, sizeof(a))
     15 #define rg register
     16 typedef long long ll;
     17 typedef double db;
     18 const int INF = 0x3f3f3f3f;
     19 const db eps = 1e-8;
     20 const int maxn = 1e3 + 5;
     21 inline ll read()
     22 {
     23     ll ans = 0;
     24     char ch = getchar(), last = ' ';
     25     while(!isdigit(ch)) {last = ch; ch = getchar();}
     26     while(isdigit(ch)) {ans = ans * 10 + ch - '0'; ch = getchar();}
     27     if(last == '-') ans = -ans;
     28     return ans;
     29 }
     30 inline void write(ll x)
     31 {
     32     if(x < 0) x = -x, putchar('-');
     33     if(x >= 10) write(x / 10);
     34     putchar(x % 10 + '0');
     35 }
     36 
     37 int n, m;
     38 int v[maxn][maxn];
     39 
     40 stack<int> st;
     41 int dfn[maxn], low[maxn], cnt = 0;
     42 vector<int> vd[maxn];
     43 int cvd = 0;
     44 void tarjan(int now, int fa)        //求点双 
     45 {
     46     dfn[now] = low[now] = ++cnt;
     47     st.push(now); 
     48     for(int i = 1; i <= n; ++i)
     49     {
     50         if(v[now][i] && now != i)
     51         {
     52             if(!dfn[i])
     53             {
     54                 tarjan(i, now);
     55                 low[now] = min(low[now], low[i]);
     56                 if(low[i] >= dfn[now])
     57                 {
     58                     int x; ++cvd;
     59                     do
     60                     {
     61                         x = st.top(); st.pop();
     62                         vd[cvd].push_back(x);
     63                     }while(x != i);
     64                     vd[cvd].push_back(now);
     65                 }
     66             }
     67             else if(i != fa) low[now] = min(low[now], dfn[i]);            
     68         }
     69 
     70     }
     71 }
     72 
     73 bool vis[maxn];
     74 int mak[maxn], col[maxn];
     75 bool dfs(int now, int flg)        //染色 
     76 {
     77     mak[now] = flg;
     78     for(int i = 1; i <= n; ++i)
     79     {
     80         if(v[now][i] && now != i && col[now] == col[i])
     81         {
     82             if(mak[i] == -1) if(dfs(i, flg ^ 1)) return 1;                    
     83             if(mak[i] == mak[now]) return 1;
     84         }
     85     }
     86     return 0;
     87 }
     88 
     89 void init()
     90 {
     91     for(int i = 0; i < maxn; ++i)
     92         for(int j = 0; j < maxn; ++j) v[i][j] = 1;
     93     for(int i = 0; i < maxn; ++i) vd[i].clear();
     94     while(!st.empty()) st.pop();
     95     Mem(dfn, 0); Mem(low, 0);
     96     cnt = cvd = 0;
     97     Mem(vis, 0); Mem(col, 0);
     98 }
     99 
    100 int main()
    101 {
    102     while(scanf("%d%d", &n, &m) && n && m)
    103     {
    104         init();
    105         for(int i = 1; i <= m; ++i)
    106         {
    107             int x = read(), y = read();
    108             v[x][y] = v[y][x] = 0;
    109         }
    110         for(int i = 1; i <= n; ++i) if(!dfn[i]) tarjan(i, 0);
    111         for(int i = 1; i <= cvd; ++i)
    112         {
    113             Mem(mak, -1);
    114             for(int j = 0; j < (int)vd[i].size(); ++j) col[vd[i][j]] = i;
    115             if(dfs(vd[i][0], 0)) 
    116                 for(int j = 0; j < (int)vd[i].size(); ++j) vis[vd[i][j]] = 1;
    117         }
    118         int ans = 0;
    119         for(int i = 1; i <= n; ++i) ans += ((int)vis[i]) ^ 1;
    120         write(ans); enter;
    121     }
    122 }
    View Code
  • 相关阅读:
    008 第八篇:爬虫实战(数据可视化之pyecharts)
    案例一 微信聊天机器人
    008 第八篇:爬虫实战
    007 第七篇:分布式爬虫
    006 第六篇:Scrapy框架
    005 第五篇:爬虫高性能相关
    004001 第四篇:存储库简单版之mongodb,redis,mysql
    003 第三篇:解析库之re、beautifulsoup、pyquery
    002 第二篇:请求库之requests,selenium
    001 第一篇:爬虫基本原理
  • 原文地址:https://www.cnblogs.com/mrclr/p/9674931.html
Copyright © 2020-2023  润新知