zoukankan      html  css  js  c++  java
  • 【和二分图判定问题的例题】

    关键词:并查集,二分图,树剖,树上差分,LCA,搜索。

    例题一:

    CodeForces-85E:Guard Towers

    题意:给定平面上N个点(N<=5000),以及N个点的坐标。现在可以把每个点染成红色或者蓝色。求最小化同色点的最大距离,且求出相应的方案数。

    思路:二分答案L,把距离大于等于L的连边,然后判定是否是二分图:  对于求方案数,ans=pow(2,cnt),cnt是连通块的数量。因为每个连通块是二分图,一个二分图的染色方案只有两种。 复杂度O(N^2*logL)。

     (当然,最优的解法是转化为切比雪夫距离,复杂度低很多,这里先不管它。)

    #include<cstdio>
    #include<vector>
    #include<cstdlib>
    #include<iostream>
    #include<algorithm>
    using namespace std;
    const int maxn=5010;
    const int Mod=1e9+7;
    vector<int>G[maxn];
    int x[maxn],y[maxn],vis[maxn],col[maxn],N;
    int qpow(int a,int x){
        int res=1;
        while(x){
            if(x&1) res=(res*1ll*a)%Mod;
            x>>=1;
            a=(a*1ll*a)%Mod;
        }   return res;
    }
    void read(int &res){
        char c=getchar();res=0;
        for(;c<'0'||c>'9';c=getchar());
        for(;c>='0'&&c<='9';c=getchar()) res=(res<<3)+(res<<1)+c-'0';
    }
    void init(int len){
        for(int i=1;i<=N;i++) vis[i]=0,G[i].clear();
        for(int i=1;i<=N;i++)
         for(int j=i+1;j<=N;j++){
              int dis=abs(x[i]-x[j])+abs(y[i]-y[j]);
              if(dis>len) {
                  G[i].push_back(j);
                  G[j].push_back(i);
              }
        }
    }
    bool dfs(int u,int opt)
    {
        vis[u]=1; col[u]=opt; 
        int L=G[u].size();
        for(int i=0;i<L;i++){
            int v=G[u][i];
            if(!vis[v]) {
                if(!dfs(v,opt^1)) return false;
            }
            else if(col[v]==opt) return false;
        }
        return true;
    }
    bool check(int len)
    {
        init(len);
        for(int i=1;i<=N;i++){
            if(!vis[i]) {
                if(!dfs(i,0)) return false;
            }
        }
        return true;
    }
    int main()
    {
        read(N); 
        for(int i=1;i<=N;i++) read(x[i]),read(y[i]);
        int L=0,R=10000,Mid,ans;
        while(L<=R){
            Mid=(L+R)>>1;
            if(check(Mid)) ans=Mid,R=Mid-1;
            else L=Mid+1;
        }
        init(ans); int cnt=0,ans2;
        for(int i=1;i<=N;i++){
            if(!vis[i]){
                cnt++;
                dfs(i,0);
            }
        }
        ans2=qpow(2,cnt);
        printf("%d
    %d
    ",ans,ans2);
        return 0;
    }
    View Code
    #include<cstdio>
    #include<vector>
    #include<cstdlib>
    #include<iostream>
    #include<algorithm>
    using namespace std;
    const int maxn=5010;
    const int Mod=1e9+7;
    int x[maxn],y[maxn],vis[maxn],col[maxn],N;
    int qpow(int a,int x){
        int res=1;
        while(x){
            if(x&1) res=(res*1ll*a)%Mod;
            x>>=1;
            a=(a*1ll*a)%Mod;
        }   return res;
    }
    void read(int &res){
        char c=getchar();res=0;
        for(;c<'0'||c>'9';c=getchar());
        for(;c>='0'&&c<='9';c=getchar()) res=(res<<3)+(res<<1)+c-'0';
    }
    bool dfs(int u,int opt,int len)
    {
        vis[u]=1; col[u]=opt; 
        for(int v=1;v<=N;v++){
            if(abs(x[u]-x[v])+abs(y[u]-y[v])<=len) continue;
            if(!vis[v]) {
                if(!dfs(v,opt^1,len)) return false;
            }
            else if(col[v]==opt) return false;
        }
        return true;
    }
    bool check(int len)
    {
        for(int i=1;i<=N;i++) vis[i]=0;
        for(int i=1;i<=N;i++){
            if(!vis[i]) {
                if(!dfs(i,0,len)) return false;
            }
        }
        return true;
    }
    int main()
    {
        read(N); 
        for(int i=1;i<=N;i++) read(x[i]),read(y[i]);
        int L=0,R=10000,Mid,ans;
        while(L<=R){
            Mid=(L+R)>>1;
            if(check(Mid)) ans=Mid,R=Mid-1;
            else L=Mid+1;
        }
        int cnt=0,ans2;
        for(int i=1;i<=N;i++) vis[i]=0;
        for(int i=1;i<=N;i++){
            if(!vis[i]){
                cnt++;
                dfs(i,0,ans);
            }
        }
        ans2=qpow(2,cnt);
        printf("%d
    %d
    ",ans,ans2);
        return 0;
    }
    View Code

    例题二:

    CodeForces-164D:Minimum Diameter

    题意:给定平面上N个点(N<=1000),以及N个点的坐标。给定K,求删去K个点后,最小化的最远距离。

    思路:同上,二分答案,把大于等于L的连边,然后就是求最小点覆盖,即每条边至少有一个点被覆盖(删去)。但是没有规律的无向图的最小点覆盖是NP问题,只能暴力,这里小小的优化一下,如果一个点的入度是1,那么显然覆盖那边边的另一个点。

    如果没有见过,两个代码都不是那么好实现(特别是第二个,哭晕)。

    例题三:

    CodeForces-19E:Fiary 

    题意:给定N点M边的无向图,问删去一条边后变为二分图的情况有哪些。

    思路:和上面两题有些不一样,不是二分+判定题。 如果存在奇环,则不是二分图。然后(blabla,总之)需要删去的边为所有奇环所共有,且不在偶环上。

    具体实现:DFS出一棵生成树,然后染色。对于剩下的没有参与生成树的边,如果两端同色,表示形成了奇环,则在奇环上每条边+1,否则在偶环上-1,最后边权对于奇环总数的边则为答案边。   +1和-1操作可以通过LCA+差分或者树剖实现。

  • 相关阅读:
    应用性能提升 要速度也要激情
    投票练习题
    租房子多条件查询练习
    JS时间戳格式化日期时间 由于mysql数据库里面存储时间存的是时间戳,取出来之后,JS要格式化一下显示。
    处理PHP字符串的10个简单方法;mysql出现乱码:character_set_server=utf8
    预定义数组(超全局数组)]
    静态方法
    类的构造方法和析构方法和封装的目的和封装的做法+访问修饰符
    面向对象与面向过程 $this的注意事项和魔术方法set和get
    PHP正则表达式;数组:for()遍历、 foreach ()遍历、each()list()组合遍历;指针遍历
  • 原文地址:https://www.cnblogs.com/hua-dong/p/8596000.html
Copyright © 2011-2022 走看看