• 9/19 深搜+网络流


    CSDN话题挑战赛第2期
    参赛话题:算法题解

    D. Decimal

    签到题,扩大1的倍数到1e18,再对n取模进行判断。

    #include
    #define int long long
    #define endl '\n'
    #define ios (ios::sync_with_stdio(false),cin.tie(0),cout.tie(0))
     
    using namespace std;
    const int N=7e6+5;
    const int inf=1e18;
    const int mod=1e9+7;
    int n;
     
    void solve()
    {
        cin>>n;
        int ans=inf;
        if(ans%n==0)
            cout<<"No"<<endl;
        else
            cout<<"Yes"<<endl;
    }
    signed main()
    {
        //ios;
        int T;cin>>T;
        while(T--)
            solve();
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28

    F. Forest Program

    本体思路倒不是很难。
    1.若是n个点构成的环,要变成树,共有2n-1种方法;
    2.稍微难想一点的时,零散的边挂在环上,都有删和不删两种选择,因此有2n种可能。
    3.两者相乘为最终答案。

    #include
    #define int long long
    #define endl '\n'
    #define ios (ios::sync_with_stdio(false),cin.tie(0),cout.tie(0))
     
    using namespace std;
    const int N=7e5+5;
    const int inf=1e18;
    const int mod=998244353;
    int n,m,pre[N],c[N],f[N],ans=1,cnt;
    int vis[N];
    vector<int>e[N];
    int qpow(int a,int b){
        int res=1;
        while(b)
        {
            if(b&1) res=res*a%mod;
            a=a*a%mod;
            b>>=1;
        }
        return res;
    }
    void dfs(int u,int fa)
    {
        vis[u]=1;
        for(int v:e[u])
        {
            if(v==fa) continue;
            if(!vis[v])
            {
                pre[v]=u;dfs(v,u);
            }
            else if(vis[v]==2) continue;
            else
            {
                int g=1,t=u;
                while(t!=v)
                {
                    g++;t=pre[t];
                }
                cnt+=g;
                ans=ans*(qpow(2,g)-1)%mod;
                //cout<
            }
        }
        vis[u]=2;
    }
    void solve()
    {
        cin>>n>>m;
        for(int i=1;i<=m;i++)
        {
            int u,v;cin>>u>>v;
            e[u].push_back(v),e[v].push_back(u);
        }
        for(int i=1;i<=n;i++)
        {
            if(!vis[i])
                dfs(i,0);
        }
        cout<<ans*qpow(2,m-cnt)%mod<<endl;
    }
    signed main()
    {
        ios;
        //int T;cin>>T;
        //while(T--)
            solve();
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70

    最大流算法概念梳理

    1.给定一个有向图,S为源点,T为汇点。
    2.每条有向边u->v有一个容量限制c,需要给每条边指定一个实际流量f,满足0<=f<=c
    3.流量平衡:出去S和T之外的每个点x,流入x的的实际流量值和等于从x流出的实际流量。
    4.最大流:从S到T的一个可行流满足从S流出的流量之和最大。

    增广路:从S到T还能运送流量的路径

    剩余流量:每条边还能提供多少流量。

    残余网络:经过最大流算法运行若干轮后的网络

    最大流算法:不选寻找增广路,知道找不到增广路。

    反向弧:方便算法进行反悔。对于每条边u->v,添加一条容量为0的反向边v->u。找到增广路之后,将对应弧的反向弧的流量加回去。

    可防止找到一条很垃圾的增广路,占用了别的增广路的空间,而反向弧可进行修复。
    最大流算法-EK :和增广的次数相关。
    Dicnic算法:也和增广次数有关,但复杂度更为优秀

    核心难点在于建图~:建立最大流的图 or 最小割的图

    最小割:给定n个点m条边的有向图,删除第i条边的代价为c[i],删除带价值之和最少的边,使得1号点出发到打不了n号点。

    在数值上,最大流=最小割。二者在思维、做法上可相互转化。

    可从最小割的理解上解决题目,再通过最大流求出最小割的值。
    Problem I. Magic Potion
    本题有两种见图方式。我刚开始写的那一种错了,刚开始想:既然一个英雄喝了药能多打死一个怪兽,那么我就假设每个英雄能打死两个怪兽,最后再和n+k取一个较小值。
    但是!wa了,想了一下原因,还是不能改变题意,要从题目基础上考虑,一个英雄打死了两个怪兽,可能会影响接下来英雄的增广路,反悔机制也不起作用。
    因此改变建图方式:
    设立两个源点和英雄相连接s、s1,s的优先级高于s1,两者间连有权值为k的边。

    #include
    //#define int long long
    #define endl '\n'
    #define For(i,a,b) for(i=(a);i<=(b);++i)
    #define ios (ios::sync_with_stdio(false),cin.tie(0),cout.tie(0))
    using namespace std;
    const int N=7e6+5;
    const int inf=1e18;
    const int mod=998244353;
    /*
    int fac[40];
    int qpow(int a,int b){
        int res=1;
        while(b)
        {
            if(b&1) res=res*a%mod;
            a=a*a%mod;
            b>>=1;
        }
        return res;
    }
    int getinv(int x){return qpow(x,mod-2);}
    int C(int a,int b)
    {
        return (fac[a]*getinv(fac[a-b])%mod)*getinv(fac[b])%mod;
    }*/
    struct edge
    {
        int to,c,nxt;
    }e[N*10];
    int n,m,k,s,s1,t;
    int head[N],idx=1;
    int d[N],cur[N];
    void add(int a,int b,int c)
    {
        e[++idx]={b,c,head[a]};
        head[a]=idx;
    }
    bool bfs()
    {
        memset(d,0,sizeof d);
        queue<int>q;
        q.push(s);
        d[s]=1;
        while(q.size())
        {
            int u=q.front();q.pop();
            for(int i=head[u];i;i=e[i].nxt)
            {
                int v=e[i].to;
                if(d[v]==0&&e[i].c)
                {
                    d[v]=d[u]+1;
                    q.push(v);
                    if(v==t) return 1;
                }
            }
        }
        return 0;
    }
    int dfs(int u,int mf)
    {
        if(u==t) return mf;
        int sum=0;
        for(int i=cur[u];i;i=e[i].nxt)
        {
            cur[u]=i;
            int v=e[i].to;
            if(d[v]==d[u]+1&&e[i].c)
            {
                int f=dfs(v,min(mf,e[i].c));
                e[i].c-=f;
                e[i^1].c+=f;
                sum+=f;
                mf-=f;
                if(mf==0) break;
            }
        }
        if(sum==0) d[u]=0;
        return sum;
    }
    int dinic()
    {
        int flow=0;
        while(bfs())
        {
            memcpy(cur,head,sizeof head);
            flow+=dfs(s,inf);
        }
        return flow;
    }
    void solve()
    {
        cin>>n>>m>>k;
        s=0,t=n+m+1,s1=n+m+2;
        for(int i=1;i<=n;i++)
            add(0,i,1),add(i,0,0);
        for(int i=1;i<=n;i++)
            add(n+m+2,i,1),add(i,n+m+2,0);
        add(s,s1,k),add(s1,s,0);
        for(int i=1;i<=m;i++)
            add(i+n,t,1),add(t,i+n,0);
        for(int i=1;i<=n;i++)
        {
            int k;cin>>k;
            for(int j=1;j<=k;j++)
            {
                int v;cin>>v;
                add(i,n+v,1),add(n+v,i,0);
            }
        }
        int ans=dinic();
        cout<<min(ans,n+k)<<endl;
    }
    signed main()
    {
        ios;
        //int T;cin>>T;
        //while(T--)
            solve();
        return 0;
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123

    第二种方式:
    更为直白一点,先跑一遍dinic,为不使用药剂的情况下杀死的怪兽;然后在补充连一下s和英雄间的边,再跑一遍dinic,与k最比较取最小值。

    void solve()
    {
        cin>>n>>m>>k;
        s=0,t=n+m+1;
        for(int i=1;i<=n;i++)
            add(0,i,1),add(i,0,0);
        for(int i=1;i<=m;i++)
            add(i+n,t,1),add(t,i+n,0);
        for(int i=1;i<=n;i++)
        {
            int k;cin>>k;
            for(int j=1;j<=k;j++)
            {
                int v;cin>>v;
                add(i,n+v,1),add(n+v,i,0);
            }
        }
        int ans=dinic();
        for(int i=1;i<=n;i++)
            add(0,i,1),add(i,0,0);
        int g=dinic();
        if(g>=k)
            cout<<ans+k<<endl;
        else
            cout<<ans+g<<endl;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
  • 相关阅读:
    基于高股息高分红优化的量化选股模型
    TiDB部署及常用命令
    【毕业设计】30-基于单片机矿井瓦斯/气体浓度/烟雾浓度报警设计(原理图+源代码+仿真+答辩论文+答辩PPT)
    郁金香2021年游戏辅助技术(初级班)(上)
    缓存过期都有哪些策略?
    vue文档网址
    zabbix5客户端安装和配置
    java 企业工程管理系统软件源码 自主研发 工程行业适用
    花了一周时间,更新了下软考云题库Web版
    (附源码)php希尔顿酒店管理系统 毕业设计 041148
  • 原文地址:https://blog.csdn.net/weixin_51934288/article/details/126931635