zoukankan      html  css  js  c++  java
  • 【YbtOJ#582】大收藏家

    题目

    题目链接:https://www.ybtoj.com.cn/contest/117/problem/2

    (Tleq 10,n,m,a_ileq 3000)

    思路

    我们只需要最大化 (1) 最终藏品数量,那么显然所有人的藏品可以看作只有一个黑色,剩余 (a_i-1) 个全部都是没有用的白色。我们需要最大化最后 (1) 号黑色的藏品数量。
    考虑如果两个人交换两个黑色的,那么其实等价于没有交换。如果交换两个白色的,那么毫无意义。所以我们肯定只让一个黑色和一个白色进行交换。
    所以我们可以把白色看作是格子,也就是任何人任何时刻的物品不能超过 (a_i) 个,每一次的“交换”其实可以看做一个人把自己的物品给另一个人。
    这很符合一个网络流模型。把所有人拆成 (m+1) 个点,从源点向所有人第一个点连一条流量为一的边。对于第 (i) 个时刻,每一个人的第 (i) 个点向第 (i+1) 个点连一条流量为 (a_i) 的边,限制最多只能有 (a_i) 个物品。如果 (x)(y) 在第 (i) 时刻交换物品,那么就在 (x,y) 的第 (i) 号点之间连一条流量为 (1) 的双向边。最后 (1) 的第 (m+1) 个点向汇点连边。
    但是这样点数是 (O(nm)) 的,不可接受。我们发现每一个时刻只需要连这个时刻有关的人的点就可以了。这样点数就降到了 (O(n+m))
    时间复杂度 (O(Tnm))

    代码

    #include <bits/stdc++.h>
    using namespace std;
    
    const int N=10010,Inf=1e9;
    int Q,S,T,n,m,maxf,tot,a[N],U[N],V[N],head[N],last[N],dep[N],cur[N];
    
    struct edge
    {
    	int next,to,flow;
    }e[N*10];
    
    void add(int from,int to,int flow)
    {
    	e[++tot]=(edge){head[from],to,flow};
    	head[from]=tot;
    	swap(from,to);
    	e[++tot]=(edge){head[from],to,0};
    	head[from]=tot;
    }
    
    bool bfs()
    {
    	memset(dep,0x3f3f3f3f,sizeof(dep));
    	memcpy(cur,head,sizeof(cur));
    	queue<int> q;
    	q.push(S); dep[S]=0;
    	while (q.size())
    	{
    		int u=q.front(); q.pop();
    		for (int i=head[u];~i;i=e[i].next)
    		{
    			int v=e[i].to;
    			if (e[i].flow && dep[v]>dep[u]+1)
    			{
    				dep[v]=dep[u]+1;
    				q.push(v);
    			}
    		}
    	}
    	return dep[T]<Inf;
    }
    
    int dfs(int x,int flow)
    {
    	if (x==T) return flow;
    	int used=0,res;
    	for (int i=cur[x];~i;i=e[i].next)
    	{
    		int v=e[i].to; cur[x]=i;
    		if (e[i].flow && dep[v]==dep[x]+1)
    		{
    			res=dfs(v,min(e[i].flow,flow-used));
    			used+=res;
    			e[i].flow-=res; e[i^1].flow+=res;
    			if (flow==used) return used;
    		}
    	}
    	return used;
    }
    
    void dinic()
    {
    	while (bfs()) maxf+=dfs(S,Inf);
    }
    
    int main()
    {
    	freopen("collection.in","r",stdin);
    	freopen("collection.out","w",stdout);
    	S=N-1; T=N-2;
    	scanf("%d",&Q);
    	while (Q--)
    	{
    		memset(head,-1,sizeof(head));
    		tot=1; maxf=0;
    		scanf("%d%d",&n,&m);
    		for (int i=1;i<=n;i++)
    		{
    			scanf("%d",&a[i]);
    			last[i]=i; add(S,i,1);
    		}
    		for (int i=1;i<=m;i++)
    		{
    			scanf("%d%d",&U[i],&V[i]);
    			add(last[U[i]],n+i*2-1,a[U[i]]);
    			add(last[V[i]],n+i*2,a[V[i]]);
    			add(n+i*2-1,n+i*2,1);
    			add(n+i*2,n+i*2-1,1);
    			last[U[i]]=n+i*2-1; last[V[i]]=n+i*2;
    		}
    		add(last[1],T,a[1]);
    		dinic();
    		printf("%d
    ",maxf);
    	}
    	return 0;
    }
    
  • 相关阅读:
    POJ 1251 Jungle Roads
    1111 Online Map (30 分)
    1122 Hamiltonian Cycle (25 分)
    POJ 2560 Freckles
    1087 All Roads Lead to Rome (30 分)
    1072 Gas Station (30 分)
    1018 Public Bike Management (30 分)
    1030 Travel Plan (30 分)
    22. bootstrap组件#巨幕和旋转图标
    3. Spring配置文件
  • 原文地址:https://www.cnblogs.com/stoorz/p/14412034.html
Copyright © 2011-2022 走看看