zoukankan      html  css  js  c++  java
  • [网络流24题] 太空飞行计划问题

    题目链接:戳我

    有木有想到最大权闭合子图呢?!(最开始刚看到题的时候以为是费用流,之后发现如果做这个实验,无论流量是多少,收益只能收取一次,这样根本无法跑费用流。。。qwqwq,之后。。只能收一次?后继节点也必须选?那肯定是闭合子图啊!!最小割嘛。。。)

    所以我们求最小割就可以了,用总的实验的收益减去最小割即是答案。

    建图:源点和每个实验连一个边,容量为实验收益。实验向自己的所需仪器连一个边,容量为INF。仪器向汇点连一个边,容量为自己需要的花费(注意,这个不是负值)qwq

    然后求最小割(就是最大流)。显然,INF的边不能割,所以只会割掉实验和源点的边(表示不做这个实验,会损失这么多的收益)或者仪器和汇点的边(表示使用这个仪器,需要多少花费)

    代码如下:

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<queue>
    #include<vector>
    #define MAXN 100010
    #define S 0
    #define T n+m+1
    using namespace std;
    int n,m,t=1,ans,all,x;
    int head[MAXN],dis[MAXN],cur[MAXN],pay[MAXN],cost[MAXN];
    char s[10000];
    bool done[MAXN];
    struct Edge{int nxt,to,dis;}edge[MAXN<<1];
    vector<int>v;
    inline void add(int from,int to,int dis)
    {
        edge[++t].nxt=head[from],edge[t].to=to,edge[t].dis=dis,head[from]=t;
        edge[++t].nxt=head[to],edge[t].to=from,edge[t].dis=0,head[to]=t;
    }
    inline void read()
    {
        int x=0,f=1; char ch=getchar();
        v.clear();
        while(ch<'0'||ch>'9')
        {
            if(ch=='-') f=1;
            ch=getchar();
        }
        while(233)
        {
            if(ch==' ') v.push_back(x*f),x=0,f=1,ch=getchar();
            else if(ch=='
    ') {v.push_back(x*f);return;}
            else x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
        }
    }
    inline bool bfs()
    {
        queue<int>q;
        memset(dis,0x3f,sizeof(dis));
        memcpy(cur,head,sizeof(head));
        memset(done,0,sizeof(done));
        q.push(S);dis[S]=0;
        while(!q.empty())
        {
            int u=q.front();q.pop();
            for(int i=head[u];i;i=edge[i].nxt)
            {
                int v=edge[i].to;
                if(edge[i].dis&&dis[v]==0x3f3f3f3f)
                    dis[v]=dis[u]+1,q.push(v),done[v]=1;
            }
        }
        if(dis[T]==0x3f3f3f3f) return false;
        return true;
    }
    inline int dfs(int x,int f)
    {
        if(!f||x==T) return f;
        int used=0,w;
        for(int i=cur[x];i;i=edge[i].nxt)
        {
            cur[x]=i;
            int v=edge[i].to;
            if(dis[v]==dis[x]+1&&(w=dfs(v,min(f,edge[i].dis))))
            {
                edge[i].dis-=w,edge[i^1].dis+=w;
                f-=w,used+=w;
                if(!f) break;
            }
        }
        return used;
    }
    inline int dinic()
    {
        int cur_ans=0;
        while(bfs()) cur_ans+=dfs(S,(int)1e9);
        return cur_ans;
    }
    int main()
    {
        #ifndef ONLINE_JUDGE
        freopen("ce.in","r",stdin);
        freopen("ce.out","w",stdout);
        #endif
        scanf("%d%d",&m,&n);
        for(int i=1;i<=m;++i)
        {
            scanf("%d",&pay[i]);
            add(S,i,pay[i]);
            all+=pay[i];
            memset(s,0,sizeof(s));
            cin.getline(s,10000);
            int j=0;
            while(sscanf(s+j,"%d",&x)==1)
            {
                if(!x)j++;
                else
                    add(i,x+m,(int)1e9);
                while(x)x/=10,j++;
                j++;
            }
        }
        for(int i=1;i<=n;i++)
        {
            scanf("%d",&cost[i]);
            add(i+m,T,cost[i]);
        }
        ans=dinic();
        for(int i=1;i<=m;i++)
            if(done[i])
                printf("%d ",i);
        printf("
    ");
        for(int i=1;i<=n;i++)
            if(done[i+m])
                printf("%d ",i);
        printf("
    ");
        printf("%d
    ",all-ans);
    }
    
  • 相关阅读:
    「SAM」你的名字
    「疫期颓废」2
    「疫期颓废」1
    代码覆盖率简单介绍
    解决git报ssh variant 'simple' does not support setting port
    接口自动化基本流程和测试思路
    wait和sleep的区别
    vm垃圾回收算法的简单理解
    TCP-三次握手和四次挥手简单理解
    浏览器输入一个url 中间经历的过程
  • 原文地址:https://www.cnblogs.com/fengxunling/p/10306320.html
Copyright © 2011-2022 走看看