zoukankan      html  css  js  c++  java
  • HDU

    题意:有最少用多少条边不重复的路径可以覆盖一个张无向图。

    分析:对于一个连通块(单个点除外),如果奇度数点个数为 k,那么至少需要max{k/2,1}  条路径。将奇度数的点两两相连边(虚边),然后先从奇度数的点出发,搜索由其出发的欧拉回路。需要将遍历的边和其反向边打标记,并在DFS退栈的时候记录边的编号(前向星的存储是访问后加入的边),若该边是自己添加的虚边,那么说明实际上这次DFS搜索到的是一条欧拉通路,那么结果还需额外+1,所以对所有奇数点DFS过后,得到的结果就是max{k/2,1}。

    再从未被访问过的偶数顶点出发搜索由其出发的欧拉回路,每一次DFS就是找到了一条回路。

    #include <cstdio>
    #include <vector>
    #include <algorithm>
    #include <cstring>
    #include <iostream>
    using namespace std;
    typedef long long LL;
    const int maxn =1e5+5;
    struct Edge{
        int to,id,next;
        bool f;
    }edges[maxn<<4];
    int tot,head[maxn],cnt;
    bool vis[maxn];
    vector<int> res[maxn];
    int deg[maxn];
    
    void init()
    {
        tot=0;
        cnt=0;
        memset(deg,0,sizeof(deg));
        memset(vis,0,sizeof(vis));
        memset(head,-1,sizeof(head));
    }
    
    void AddEdge(int u,int v ,int id)
    {
        edges[tot].f = 0;edges[tot].to=v;edges[tot].id = id;edges[tot].next =head[u];
        head[u]=tot++;
    }
    
    void dfs(int u)
    {
        vis[u]=true;
        //cout<<u<<" in "<<cnt<<endl;
        for(int i=head[u];~i;i=edges[i].next){
            int v =edges[i].to,id =edges[i].id;
            if(!edges[i].f){
                edges[i].f = edges[i^1].f = true;       //将边和反向边标记
                dfs(v);
                if(id) res[cnt].push_back(-id);     //退栈记录边的id
                else cnt++;                         //扫到虚边,那么路径加1
                //cout<<u<<" out "<<cnt<<endl;
            }
        }
    }
    
    void Print()
    {
        printf("%d
    ",cnt);
            for(int i=1;i<=cnt;++i){
                printf("%d",res[i].size());
                int k = res[i].size();
                for(int j=0;j<k;++j) printf(" %d",res[i][j]);
                printf("
    ");
                res[i].clear();  
        }
    }
    
    int main()
    {
        #ifndef ONLINE_JUDGE
            freopen("in.txt","r",stdin);
            freopen("out.txt","w",stdout);
        #endif
        int T,N,M,u,v,tmp;
        while(scanf("%d%d",&N,&M)==2){
            init();
            for(int i=1;i<=M;++i){
                scanf("%d%d",&u,&v);
                deg[u]++,deg[v]++;
                AddEdge(u,v,i);
                AddEdge(v,u,-i);
            }
            u=0;
            for(int i=1;i<=N;++i){
                if(deg[i]&1){
                    if(u){ 
                        AddEdge(u,i,0);
                        AddEdge(i,u,0);
                        u=0;  
                    }          //将奇度数点两两连边
                    else u=i;
                }
            }
            for(int i=1;i<=N;++i){
                if(!vis[i] && (deg[i]&1)){   
                    cnt++;  
                    dfs(i);
                    cnt--;
                }
            }
            for(int i=1;i<=N;++i){
                if(!vis[i] && deg[i]){
                    cnt++;
                    dfs(i);
                }
            }
            Print();
        }
        return 0;
    }
     
    为了更好的明天
  • 相关阅读:
    3D打印技术大潮
    有用网址
    linux下scp命令详解
    使用 GDB 调试多进程程序
    linux下top命令参数解释
    Sql动态查询拼接字符串的优化
    vmstat参数详解
    freebsd破解密码
    freebsd防火墙
    freebsd无法输入汉字
  • 原文地址:https://www.cnblogs.com/xiuwenli/p/9372062.html
Copyright © 2011-2022 走看看