zoukankan      html  css  js  c++  java
  • 【BZOJ-2893】征服王 最大费用最大流(带下界最小流)

    2893: 征服王

    Time Limit: 10 Sec  Memory Limit: 256 MB
    Submit: 156  Solved: 48
    [Submit][Status][Discuss]

    Description

    虽然春希将信息传递给了雪菜,但是雪菜却好像完全不认得春希了。心急如焚的春希打开了第二世代机能,对雪菜的脑内芯片进行了直连-hack。
    进入到雪菜内部的春希发现(这什么玩意。。),雪菜的脑部结构被分成了n个块落,并且一些块落之间被有向边连接着。由于四分五裂的脑部,雪菜关于春希的记忆也完全消失,春希为了恋人,启动了inversionprocess.
    在inversion process中,要想使雪菜回到正常状态,需要纳米机器人的帮助。纳米机器人可以从任意一个可以作为起点的块落出发进行修复,也可以在任意一个可以作为终点的块落结束修复(并不是到了某个终点就一定要停止)。春希希望所有的节点都能被修复(只要纳米机器人到过该点就算修复过),这样才能让雪菜重获新生。
    作为纳米机器人1号的你能帮助春希算算至少需要多少个机器人才能拯救雪菜吗?
    当然,如果无论如何都无法使得春希的愿望被满足的话,请输出”no solution”(不包括引号)

    Input

    题目包含多组数据
    第1行有一个正整数t,表示数据的组数。
    第2行有两个正整数n、m,a,b,分别表示块落的数量、有向边的数量、起点的数量、终点的数量。
    第3行有a个正整数,表示可以作为起点的块落。
    第4行有b个正整数,表示可以作为终点的块落。
    第5行至第m+4行,每行有两个正整数u、v,表示能从编号为u的块落到编号为v的块落。
    之后以此类推。

    Output

    输出共有t行,每行输出对应数据的答案。

    Sample Input


    2
    2 1 1 1
    1
    2
    2 1
    3 2 3 3
    1 2 3
    1 2 3
    1 2
    1 3

    Sample Output


    no solution
    2
    【数据规模和约定】
    对于30%的数据,满足n <= 10, m <= 100。
    对于60%的数据,满足n <= 200, m <= 5000。
    对于100%的数据,满足t<=10,n <= 1000, m <= 10000。

    HINT

    Source

    Solution

    一眼网络流,起点终点有限制的最小路径覆盖

    一般的最小路径覆盖问题,是用二分图的方法去解

    而这里,应该考虑另一种做法

    对于有向图,先Tarjan缩点,重建图,然后求带下届的最小流即可

    但是这里用的最大费用最大流,同时需要缩点,建图:

    对于Tarjan后缩成的点,每个点拆成两个点,入点向出点连两条边,容量inf,费用0;容量1,费用1

    原图中的点,缩成的点相连,容量inf,费用1

    S到起始点缩成的点连容量inf,费用0

    T到终止点缩成的点连容量inf,费用0

    然后跑最大费用最大流,因为最大费用最大流每次增广的费用是严格从大到小的,所以增广次数既为答案

    Code

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #include<cmath>
    #include<queue>
    using namespace std;
    int read()
    {
        int x=0,f=1; char ch=getchar();
        while (ch<'0' || ch>'9') {if (ch=='-') f=-1; ch=getchar();}
        while (ch>='0' && ch<='9') {x=x*10+ch-'0'; ch=getchar();}
        return x*f;
    }
    #define maxm 100100
    #define maxn 2010
    int n,m,A,B,t,ans,cost;
    struct Edgenode{int to,next,cap,cost,from;}edge[maxm];
    int head[maxn],cnt;
    inline void add(int u,int v,int w,int c) 
    { 
        cnt++; edge[cnt].next=head[u]; head[u]=cnt; 
        edge[cnt].from=u; edge[cnt].to=v; edge[cnt].cap=w; edge[cnt].cost=c; 
    } 
    inline void insert(int u,int v,int w,int c) 
    {add(u,v,w,c); add(v,u,0,-c);} 
    struct Roadnode{int to,next;}road[maxm];
    int last[maxn],cnr;
    inline void Add(int u,int v) 
    { 
        cnr++; road[cnr].next=last[u]; last[u]=cnr; road[cnr].to=v;
    } 
    #define inf 0x7fffffff
    int S,T; int dis[maxn]; queue<int>q; bool mark[maxn];
    inline bool spfa() 
    { 
        
        memset(mark,0,sizeof(mark)); 
        for (int i=0; i<=S; i++) dis[i]=-1; 
        q.push(T); mark[T]=1; dis[T]=0; 
        while (!q.empty()) 
            { 
                int now=q.front(); q.pop(); 
                for (int i=head[now]; i; i=edge[i].next) 
                    if (edge[i^1].cap && dis[edge[i].to]<dis[now]+edge[i^1].cost) 
                        { 
                            dis[edge[i].to]=dis[now]+edge[i^1].cost; 
                            if (!mark[edge[i].to]) 
                                mark[edge[i].to]=1,q.push(edge[i].to); 
                        } 
                mark[now]=0; 
              //  printf("%d %d %d
    hahahaha",now,he,ta);
            } 
        return dis[S]!=-1; 
    } 
    inline int dfs(int loc,int low) 
    { 
        mark[loc]=1; 
        if (loc==T) return low; 
        int w,used=0; 
        for (int i=head[loc]; i; i=edge[i].next) 
            if (edge[i].cap && dis[edge[i].to]==dis[loc]-edge[i].cost && !mark[edge[i].to]) 
                { 
                    w=dfs(edge[i].to,min(low-used,edge[i].cap)); 
                    edge[i].cap-=w; edge[i^1].cap+=w; used+=w; 
                    cost+=w*edge[i].cost; if (used==low) return low; 
                } 
        return used; 
    } 
    inline void zkw() 
    { 
        while (spfa()) 
            { 
                int pre=cost;
                mark[T]=1; 
                while (mark[T]) 
                    {memset(mark,0,sizeof(mark)); dfs(S,inf);}
                insert(S,0,1,0);
                if (pre==cost) break; else ans++;
            }
    //    printf("%d %d %d
    ",cnt,cost,ans);
    }
    int stack[maxn],top,dfn[maxn],low[maxn],tot,qcnt,belong[maxn]; bool visit[maxn];
    void Tarjan(int x) 
    { 
        dfn[x]=low[x]=++tot; 
        visit[x]=1; stack[++top]=x; 
        for (int i=last[x]; i; i=road[i].next) 
            { 
                if (!dfn[road[i].to]) 
                    { 
                        Tarjan(road[i].to); 
                        if (low[road[i].to]<low[x]) low[x]=low[road[i].to]; 
                    } 
                else 
                    if(visit[road[i].to] && dfn[road[i].to]<low[x]) 
                        low[x]=dfn[road[i].to]; 
            } 
        if (dfn[x]==low[x]) 
            { 
                int uu=0;qcnt++; 
                while (x!=uu) 
                    uu=stack[top--],visit[uu]=0,belong[uu]=qcnt;  
            } 
    } 
    inline void init()
    {
        memset(dfn,0,sizeof(dfn));
        memset(head,0,sizeof(head));
        memset(last,0,sizeof(last)); 
        cnt=1; cnr=top=tot=qcnt=cost=ans=0;
    }
    int cans[maxn],cant[maxn];
    inline void rebuild()
    {
        T=2*qcnt+1;S=T+1;
        for (int i=1; i<=A; i++) insert(0,belong[cans[i]],inf,0);
        for (int i=1; i<=B; i++) insert(belong[cant[i]]+qcnt,T,inf,0);
        for (int u=1; u<=n; u++)
            for (int i=last[u]; i; i=road[i].next)
                if (belong[u]!=belong[road[i].to])
                    insert(belong[u]+qcnt,belong[road[i].to],inf,0);
        for (int i=1; i<=qcnt; i++) insert(i,i+qcnt,1,1),insert(i,i+qcnt,inf,0);
        insert(S,0,1,0);
    }
    int main()
    {
    //    freopen("sail.in","r",stdin);
    //    freopen("sail.out","w",stdout);
        t=read();
        while (t--)
            {
                init();
                n=read(),m=read(),A=read(),B=read();
                for (int i=1; i<=A; i++) cans[i]=read();
                for (int i=1; i<=B; i++) cant[i]=read();
                for (int u,v,i=1; i<=m; i++) u=read(),v=read(),Add(u,v);
                for (int i=1; i<=n; i++) if (!dfn[i]) Tarjan(i);
                rebuild();
                zkw();
                if (cost!=qcnt) puts("no solution");
                    else printf("%d
    ",ans);
            }
        return 0;
    }

    这题自己默默T成狗,改了好久

  • 相关阅读:
    解决shiro多次从redis读取session的问题
    软件测试其他方法
    异常HTTP Status 500
    支付
    java面试
    SQL入门
    软件测试理论基础
    软件测试学习第一章
    Linux在终端命令行模式下智能补全功能以及组合键
    Linux安装
  • 原文地址:https://www.cnblogs.com/DaD3zZ-Beyonder/p/5450399.html
Copyright © 2011-2022 走看看