• YbtOJ大收藏家【分层图,最大流】


    正题

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


    题目大意

    \(n\)个人,每人有\(a_i\)个属于自己的物品。\(m\)次交换依次进行,每次\(x_i,y_i\)两个人可以决定拿不拿自己的一个物品进行交换。

    \(1\)号人最后能拿到最多多少种物品

    \(1\leq n,m,a_i\leq 3000\)


    解题思路

    每种物品只需要一个,所以每种物品的第一个可以视为流量,\(a_i\)可以视为自己的物品处的空位(自己的物品可以不视为自己的)。

    \(x_i,y_i\)的交换可以视为一条流量为\(1\)的双向边,因为依次进行所以要分成\(m\)层,然后每一层有交换的连边。

    发现这样有很多点没有用到,去掉这些多余的,那点数就是\(O(n+m)\)级别的了

    跑最大流就好了


    code

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<queue>
    using namespace std;
    const int N=12100,inf=1e9;
    struct node{
    	int to,next,w;
    }a[N<<2];
    int T,n,m,tot,cnt,ans,s,t;
    int ls[N],dep[N],p[N],w[N];
    queue<int> q;
    void addl(int x,int y,int w){
    	a[++tot].to=y;a[tot].next=ls[x];ls[x]=tot;a[tot].w=w;
    	a[++tot].to=x;a[tot].next=ls[y];ls[y]=tot;a[tot].w=0;
    	return;
    }
    bool bfs(){
    	memset(dep,0,sizeof(dep));dep[s]=1;
    	while(!q.empty())q.pop();q.push(s);
    	while(!q.empty()){
    		int x=q.front();q.pop();
    		for(int i=ls[x];i;i=a[i].next){
    			int y=a[i].to;
    			if(dep[y]||!a[i].w)continue;
    			dep[y]=dep[x]+1;
    			if(y==t)return 1;
    			q.push(y);
    		} 
    	}
    	return 0;
    }
    int dinic(int x,int flow){
    	if(x==t)return flow;
    	int rest=0,k;
    	for(int i=ls[x];i;i=a[i].next){
    		int y=a[i].to;
    		if(dep[x]+1!=dep[y]||!a[i].w)continue;
    		rest+=(k=dinic(y,min(a[i].w,flow-rest)));
    		a[i].w-=k;a[i^1].w+=k;
    		if(rest==flow)return rest;
    	}
    	if(!rest)dep[x]=0;
    	return rest;
    }
    int main()
    {
    	freopen("collection.in","r",stdin);
    	freopen("collection.out","w",stdout);
    	scanf("%d",&T);
    	while(T--){
    		tot=0;memset(ls,0,sizeof(ls));
    		scanf("%d%d",&n,&m);
    		s=tot=1;t=cnt=2;ans=0;
    		for(int i=1;i<=n;i++){
    			p[i]=++cnt;
    			scanf("%d",&w[i]);
    			addl(s,p[i],1);
    		}
    		for(int i=1;i<=m;i++){
    			int x,y;scanf("%d%d",&x,&y);
    			++cnt;addl(p[x],cnt,w[x]);p[x]=cnt;
    			++cnt;addl(p[y],cnt,w[y]);p[y]=cnt;
    			addl(p[x],p[y],1);addl(p[y],p[x],1);
    		}
    		addl(p[1],t,inf);
    		while(bfs())
    			ans+=dinic(s,inf);
    		printf("%d\n",ans);
    	}
    	return 0;
    }
    
  • 相关阅读:
    delphi操作xml学习笔记 之一 入门必读
    Delphi中实现ListView滚动条的换肤方案
    关于CreateParams的参数
    Delphi中编写OwnerDraw方式按钮的方法以及注意点
    ClientDataSet使用心得和技巧
    ADO多线程
    SQL的单个表的大小限制最大可以是多大?
    TClientDataSet使用要点
    鼠标拖动窗体
    Delphi托盘类 收集
  • 原文地址:https://www.cnblogs.com/QuantAsk/p/14412567.html
Copyright © 2020-2023  润新知