码迷,mamicode.com
首页 > 其他好文 > 详细

P1231 教辅的组成

时间:2019-01-13 16:09:41      阅读:160      评论:0      收藏:0      [点我收藏+]

标签:turn   color   pac   max   这一   更新   class   scanf   use   

  滴了两个小时了qwq……总算是过了(泪奔)……

  首先,这道题写网络流不难,看出来是网络流才难。

  可是我呢,我一眼就看出来是网络流,可是一直tle。

  其实我是通过标签看出来的>\\\<~

  你什么都没看见,嗯。

  咳咳,我正经点……为什么可以用网络流呢,就是因为同种的点(就是题中书的类别)之间没有连边,所以一条边如果能为最大流提供帮助,那么这条边一定是在一条从头到尾的链中,这条链就是一个组合。那么可得:最多成功到达汇点的边数,就是最大多的组合数。那么,当边权都为1时,最大流就是最多的组合数。

  可是有一个问题,就是中间点(书)可能被重复利用,因为我们之定义了边的容量,而没有定义点的容量。所以,我们就将所有的中间点(书),拆成左右两个点,中间连一条边权为1的边就可以了。

  就算你做到这一步,也不能A……

  你得保证你的dinic够快……所以你要优化一下,保证已经不能更新的那些路的起点,在这个增广路中,不需要再一次走(不要踏上不归路)。

  代码:

#include<cstdio>
#include<iostream>
#include<cstring>
#include<queue>
using namespace std; 
const int maxn=1e6+5;
const int inf=1e9;
struct node
{
    int nxt=-1,to,w;
} edge[maxn];
int head[maxn],dep[maxn];
int n,m,s,t,k,cnt=-1;
void add(int a,int b,int c)
{
    edge[++cnt].to=b;
    edge[cnt].nxt=head[a];
    head[a]=cnt;
    edge[cnt].w=c;
}
int dfs(int u,int dist)
{
    if(u==t) return dist;
    int used=0,d=0;
    for(int i=head[u];i!=-1;i=edge[i].nxt)
    {
        int to=edge[i].to;
        if(dep[to]==dep[u]+1&&edge[i].w)
        {
            if(d=dfs(to,min(dist-used,edge[i].w)))
            {
                edge[i].w-=d;
                edge[i^1].w+=d;
                used+=d;
            }
        }
    }
    if(!used) dep[u]=0;
    return used;
}
int bfs()
{
    memset(dep,0,sizeof(dep));
    queue<int> q;
    while(!q.empty()) q.pop();
    dep[s]=1;
    q.push(s); 
    while(!q.empty())
    {
        int u=q.front();
        q.pop();
        for(int i=head[u];i!=-1;i=edge[i].nxt)
        {
            int to=edge[i].to;
            if(edge[i].w&&!dep[to])
            {
                dep[to]=dep[u]+1;
                q.push(to);
            }
        }
    }
    if(!dep[t]) return 0;
    else return 1; 
}
int dinic()
{
    int ans=0;
    while(bfs())
    {
        while(int di=dfs(s,inf))
            ans+=di;
    }
    return ans;
}
int main()
{
    memset(head,-1,sizeof(head));
    scanf("%d%d%d",&n,&m,&k);
    s=0,t=2*n+m+k+1;
    int e;
    scanf("%d",&e);
    for(int i=1;i<=e;i++)
    {
        int x,y;
        scanf("%d%d",&x,&y);
        add(y,x+m,1);
        add(x+m,y,0);
    }
    scanf("%d",&e);
    for(int i=1;i<=e;i++)
    {
        int x,y;
        scanf("%d%d",&x,&y);
        add(x+n+m+k,n+m+y,1);
        add(n+m+y,x+n+m+k,0);
    }
    for(int i=1;i<=m;i++)
    {
        add(s,i,1);
        add(i,s,1);
    }
    for(int i=m+1;i<=m+n;i++)
    {
        add(i,i+n+k,1);
        add(i+n+k,i,0);
    }
    for(int i=m+n+1;i<=m+n+k;i++)
    {
        add(i,t,1);
        add(t,i,0);
    }
    printf("%d",dinic());
    return 0;
}

   赶紧——复习去!

P1231 教辅的组成

标签:turn   color   pac   max   这一   更新   class   scanf   use   

原文地址:https://www.cnblogs.com/popo-black-cat/p/10262690.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!