• 网络流


    A.蜥蜴

    将每个石柱拆点,最多可起跳石柱的高度次,入点向出点连其高度的边。

    两个石柱平面距离不超过d时可互相到达,由一个石柱的出点向另一个石柱的入点连$Inf$边。

    建立源点和汇点。

      当前石柱有蜥蜴时,源点$s$向该石柱入点连容量为$1$的边。

      当前石柱的横或纵坐标距离边界最短距离$<d$时,该石柱出点向汇点$t$连$Inf$边。

    跑最大流就是可逃出去最多的蜥蜴数,用总蜥蜴数减去即可。

    #include <bits/stdc++.h>
    #define Inf 0x3f3f3f3f
    using namespace std;
    int n,m,d,S,t,ans;
    char s[25];
    const int maxn=805;
    int cnt=-1,head[maxn],vis[maxn];
    struct Edge{
        int to,next,w;
    }e[maxn*maxn];
    void add(int u,int v,int w) {
        e[++cnt].to=v;
        e[cnt].w=w;
        e[cnt].next=head[u];
        head[u]=cnt;
        e[++cnt].to=u;
        e[cnt].next=head[v];
        head[v]=cnt;
    }
    bool Judge(int x,int y,int xx,int yy) {
        double temp=sqrt((x-xx)*(x-xx)+(y-yy)*(y-yy));
        return temp<=d;
    }
    queue<int>q;
    bool bfs() {
        q.push(S);
        memset(vis,0,sizeof(vis));
        vis[S]=1;
        while(!q.empty()) {
            int u=q.front();
            q.pop();
            for(int i=head[u];~i;i=e[i].next) {
                int v=e[i].to;
                if(e[i].w&&!vis[v]) {
                    vis[v]=vis[u]+1;
                    q.push(v);
                }
            }
        }
        return vis[t];
    }
    int dfs(int u,int flow) {
        if(u==t) return flow;
        int temp=0,w;
        for(int i=head[u];~i;i=e[i].next) {
            int v=e[i].to;
            if(e[i].w&&vis[v]==vis[u]+1) {
                w=dfs(v,min(flow-temp,e[i].w));
                e[i].w-=w,e[i^1].w+=w,temp+=w;
                if(temp==flow) return temp;
            }
        }
        if(!temp) vis[u]=0;
        return temp;
    }
    int dinic() {
        int res=0;
        while(bfs()) res+=dfs(S,Inf);
        return res;
    }
    int main() {
        memset(head,-1,sizeof(head));
        scanf("%d%d%d",&n,&m,&d);
        S=0,t=n*m*2+1;
        for(int i=1;i<=n;++i) {
            scanf("%s",s+1);
            for(int j=1;j<=m;++j) {
                if(s[j]!='0') add((i-1)*m+j,(i-1)*m+j+n*m,s[j]-'0');
            }
        }
        for(int i=1;i<=n;++i) {
            scanf("%s",s+1);
            for(int j=1;j<=m;++j) {
                if(s[j]=='L') add(S,(i-1)*m+j,1),ans++;
            }
        }
        for(int i=1;i<=n;++i) {
            for(int j=1;j<=m;++j) {
                if(i-d<1||i+d>n||j-d<1||j+d>m) add((i-1)*m+j+n*m,t,Inf);
            }
        }
        for(int i=1;i<=n;++i) {
            for(int j=1;j<=m;++j) {
                for(int u=1;u<=n;++u) {
                    for(int v=1;v<=m;++v) {
                        if(Judge(i,j,u,v)) add((i-1)*m+j+n*m,(u-1)*m+v,Inf);
                    }
                }
            }
        }
        printf("%d
    ",ans-dinic());
        return 0;
    }
    View Code

    B.星际战争

    每个激光武器向可攻击的机器人连一条$Inf$边。

    机器人向汇点连自己的装甲值。

    二分答案 每次二分需要的时间$t$,重建汇点向每个激光武器连$B[i] imes t$容量的边,检验最后$A[i]$是否满流。

    处理精度问题可用$long double$,或者因为题目要求精度为$10^{-3}$可将其$ imes 1000$,最后输出答案时除回去即可。

    邻接表清空时不仅$cnt$和$head$数组要初始化,链表$e$也要重置

    #include<bits/stdc++.h>
    #define Inf 0x3f3f3f3f3f3f3f3f
    using namespace std;
    const int maxn=50+5;
    int n,m,a[maxn],b[maxn],s,t;
    bool mapp[maxn][maxn];
    int cnt=-1,head[maxn<<1],vis[maxn<<1];
    typedef long long ll;
    ll sum;
    struct Edge{
        int to,next;
        ll w;
    }e[maxn*maxn<<1];
    void add(int u,int v,ll w) {
        e[++cnt].to=v;
        e[cnt].w=w;
        e[cnt].next=head[u];
        head[u]=cnt;
        e[++cnt].to=u;
        e[cnt].next=head[v];
        head[v]=cnt;
    }
    queue<int>q;
    bool bfs() {
        q.push(s);
        memset(vis,0,sizeof(vis));
        vis[s]=1;
        while(!q.empty()) {
            int u=q.front();
            q.pop();
            for(int i=head[u];~i;i=e[i].next) {
                int v=e[i].to;
                if(e[i].w&&!vis[v]) {
                    vis[v]=vis[u]+1;
                    q.push(v);
                }
            }
        }
        return vis[t];
    }
    ll dfs(int u,ll flow) {
        if(u==t) return flow;
        ll temp=0,w;
        for(int i=head[u];~i;i=e[i].next) {
            int v=e[i].to;
            if(e[i].w&&vis[v]==vis[u]+1) {
                w=dfs(v,min(flow-temp,e[i].w));
                e[i].w-=w,e[i^1].w+=w,temp+=w;
                if(flow==temp) return flow;
            }
        }
        if(!temp) vis[u]=0;
        return temp;
    }
    ll dinic() {
        ll res=0;
        while(bfs()) res+=dfs(s,Inf);
        return res;
    }
    bool Judge(ll mid) {
        cnt=-1;
        memset(head,-1,sizeof(head));
        memset(e,0,sizeof(e));
        for(int i=1;i<=n;++i) add(i+m,t,a[i]);
        for(int i=1;i<=m;++i)
            for(int j=1;j<=n;++j)
                if(mapp[i][j]) add(i,j+m,Inf);
        for(int i=1;i<=m;++i) add(s,i,mid*b[i]);
        return dinic()>=sum;
    }
    int main() {
        scanf("%d%d",&n,&m);
        s=0,t=n+m+1;
        for(int i=1;i<=n;++i) scanf("%d",&a[i]),a[i]=a[i]*1000,sum+=a[i];
        for(int i=1;i<=m;++i) scanf("%d",&b[i]);
        for(int i=1;i<=m;++i)
            for(int j=1;j<=n;++j)
                scanf("%d",&mapp[i][j]);
        ll l=0,r=5e9,mid;
        while(l<=r) {
            mid=l+r>>1LL;
            if(Judge(mid)) r=mid-1;
            else l=mid+1;
        }
        printf("%lf
    ",(double)l/1000);
        return 0;
    }
    View Code

    D.士兵占领

    源点连行坐标,汇点连纵坐标。

    反向思考,边容量设置为其最多可不放置的士兵数,假设最初所有能放置士兵的位置先都放置士兵。

    行列无障碍,建立一条容量为$1$的边。

    跑出的最大流就是在符合题意的前提下,最多能不放置的士兵数。

    #include <bits/stdc++.h>
    #define Inf 0x3f3f3f3f
    using namespace std;
    const int maxn=100+5;
    int m,n,k,s,t,hang[maxn],lie[maxn],x,y;
    bool mapp[maxn][maxn];
    int cnt=-1,head[maxn<<1],vis[maxn<<1];
    struct Edge{
        int to,next,w;
    }e[maxn*maxn<<1];
    void add(int u,int v,int w) {
        e[++cnt].to=v;
        e[cnt].w=w;
        e[cnt].next=head[u];
        head[u]=cnt;
        e[++cnt].to=u;
        e[cnt].next=head[v];
        head[v]=cnt;
    }
    queue<int>q;
    bool bfs() {
        memset(vis,0,sizeof(vis));
        q.push(s);
        vis[s]=1;
        while(!q.empty()) {
            int u=q.front();
            q.pop();
            for(int i=head[u];~i;i=e[i].next) {
                int v=e[i].to;
                if(e[i].w&&!vis[v]) {
                    vis[v]=vis[u]+1;
                    q.push(v);
                }
            }
        }
        return vis[t];
    }
    int dfs(int u,int flow) {
        if(u==t) return flow;
        int temp=0,w;
        for(int i=head[u];~i;i=e[i].next) {
            int v=e[i].to;
            if(e[i].w&&vis[v]==vis[u]+1) {
                w=dfs(v,min(flow-temp,e[i].w));
                e[i].w-=w,e[i^1].w+=w,temp+=w;
                if(temp==flow) return temp;
            }
        }
        if(!temp) vis[u]=0;
        return temp;
    }
    int dinic() {
        int res=0;
        while(bfs()) res+=dfs(s,Inf);
        return res;
    }
    int main() {
        s=0,t=n+m+1;
        memset(head,-1,sizeof(head));
        scanf("%d%d%d",&n,&m,&k);
        for(int i=1;i<=n;++i) scanf("%d",&hang[i]),hang[i]=m-hang[i];
        for(int i=1;i<=m;++i) scanf("%d",&lie[i]),lie[i]=n-lie[i];
        int flag=0;
        for(int i=1;i<=k;++i) {
            scanf("%d%d",&x,&y);
            mapp[x][y]=1;
            hang[x]--,lie[y]--;
            if(hang[x]<0||lie[x]<0) flag=1;
        }
        if(flag) printf("JIONG!
    ");
        else {
            for(int i=1;i<=n;++i) add(s,i,hang[i]);
            for(int i=1;i<=m;++i) add(i+n,t,lie[i]);
            for(int i=1;i<=n;++i) {
                for(int j=1;j<=m;++j) {
                    if(!mapp[i][j]) add(i,j+n,1);
                }
            }
        }
        printf("%d
    ",n*m-k-dinic());
        return 0;
    }
    View Code

    H.最大获利

    最大权闭合子图简单模型。

    每个用户群设置一个节点,源点$s$向其连可获得收益为$w[i]$的边,节点向两个所需的中转站连$Inf$边。

    每个中转站向汇点$t$连建立它所需的费用$p[i]$的边。

    初始设置服务所有用户群,$sum=$获利$w[i]$的总和,在上图中跑最小割。

    割边不会为$Inf$边,那么就只会为$w[i]$或$p[i]$的边:

      割$w[i]$时代表失去该用户群;

      反之保留该用户群,花费对应的$p[i]$建立中转站。

    答案为$sum-$最小割。

    #include <bits/stdc++.h>
    #define Inf 0x3f3f3f3f
    using namespace std;
    const int maxn=6e4+5;
    int n,m,x,y,z,s,t,ans;
    int cnt=-1,head[maxn],vis[maxn];
    struct Edge{
        int to,next,w;
    }e[maxn*6];
    void add(int u,int v,int w) {
        e[++cnt].to=v;
        e[cnt].w=w;
        e[cnt].next=head[u];
        head[u]=cnt;
        e[++cnt].to=u;
        e[cnt].next=head[v];
        head[v]=cnt;
    }
    queue<int>q;
    bool bfs() {
        memset(vis,0,sizeof(vis));
        q.push(s);
        vis[s]=1;
        while(!q.empty()) {
            int u=q.front();
            q.pop();
            for(int i=head[u];~i;i=e[i].next) {
                int v=e[i].to;
                if(e[i].w&&!vis[v]) {
                    vis[v]=vis[u]+1;
                    q.push(v);
                }
            }
        }
        return vis[t];
    }
    int dfs(int u,int flow) {
        if(u==t) return flow;
        int temp=0,w;
        for(int i=head[u];~i;i=e[i].next) {
            int v=e[i].to;
            if(e[i].w&&vis[v]==vis[u]+1) {
                w=dfs(v,min(flow-temp,e[i].w));
                e[i].w-=w,e[i^1].w+=w,temp+=w;
                if(flow==temp) return temp;
            }
        }
        if(!temp) vis[u]=0;
        return temp;
    }
    int dinic() {
        int res=0;
        while(bfs()) res+=dfs(s,Inf);
        return res;
    }
    int main() {
        memset(head,-1,sizeof(head));
        scanf("%d%d",&n,&m);
        s=0,t=n+m+1;
        for(int i=1;i<=n;++i) scanf("%d",&x),add(i,t,x);
        for(int i=1;i<=m;++i) scanf("%d%d%d",&x,&y,&z),add(i+n,x,Inf),add(i+n,y,Inf),add(s,i+n,z),ans+=z;
        printf("%d
    ",ans-dinic());
        return 0;
    }
    View Code
  • 相关阅读:
    查看线程
    shiro+多tomcat+redis实现session共享
    win11系统设置笔记本合盖上不休眠
    nvm切换node版本出现乱码 exit status 1:
    nvm安装vuecli
    SQL Server Management 2012 启动错误及解决:Cannot find one or more componets
    SQL Server 2012 连接 Oracle 11gR2 Database
    SQL Server 数据库跨区域时间问题
    SSIS 同步不同数据库的不同两张表
    Reporting Service 不能发送订阅报表的问题
  • 原文地址:https://www.cnblogs.com/1999-09-21Karry-erfs/p/13962400.html
Copyright © 2020-2023  润新知