zoukankan      html  css  js  c++  java
  • 【刷题】BZOJ 5154 [Tjoi2014]匹配

    Description

    有N个单身的男孩和N个单身女孩,男孩i和女孩j在一起得到的幸福值为Hij。一个匹配即对这N个男孩女孩的安排:

    每个男孩恰好有一个女朋友,每个女孩恰好有一个男朋友。一个匹配的幸福值即这N对男女朋友的幸福值的和。经典的问题是计算幸福值最大的匹配,即完美匹配。然而完美匹配有时候并不唯一,你需要计算,对于所有的完美匹配,其交集是什么。

    Input

    输入的第一行是一个正整数N。N ≤ 80

    接下来是一个N*N大小的矩阵H,Hij表示男孩i和女孩j在一起的幸福值。(0≤Hij≤5000)

    Output

    第一行输出完美匹配的幸福值

    接下来是若干行,每一行是一对整数i和j,表示男孩i和女孩j在所有完美匹配的交集中。以i的递增顺序输出

    Sample Input

    3
    1 1 1
    2 1 1
    1 1 1

    Sample Output

    4
    2 1

    Solution

    数据范围够小
    所以直接先跑一遍费用流,把集合中的边记下来
    然后枚举这些边,把这些边从图中删掉,再跑费用流,如果跑出来的结果和最开始的结果一样,说明存在完美匹配不包括当前边,标记下来
    最后存在集合里并且没有被标记的边就是答案

    #include<bits/stdc++.h>
    #define ui unsigned int
    #define ll long long
    #define db double
    #define ld long double
    #define ull unsigned long long
    const int MAXN=80+10,inf=0x3f3f3f3f;
    int n,e=1,s,t,beg[MAXN<<1],cur[MAXN<<1],p[MAXN<<1],level[MAXN<<1],to[MAXN*MAXN*2],nex[MAXN*MAXN*2],cap[MAXN*MAXN*2],was[MAXN*MAXN*2],G[MAXN][MAXN],ans_was,vis[MAXN<<1],clk,out[MAXN*MAXN<<1],M[MAXN][MAXN],stand,cnt;
    std::queue<int> q;
    struct side{
    	int x,y;
    	inline bool operator < (const side &A) const {
    		return x<A.x||(x==A.x&&y<A.y);
    	};
    };
    side match[MAXN*MAXN],ans[MAXN*MAXN];
    template<typename T> inline void read(T &x)
    {
    	T data=0,w=1;
    	char ch=0;
    	while(ch!='-'&&(ch<'0'||ch>'9'))ch=getchar();
    	if(ch=='-')w=-1,ch=getchar();
    	while(ch>='0'&&ch<='9')data=((T)data<<3)+((T)data<<1)+(ch^'0'),ch=getchar();
    	x=data*w;
    }
    template<typename T> inline void write(T x,char ch='')
    {
    	if(x<0)putchar('-'),x=-x;
    	if(x>9)write(x/10);
    	putchar(x%10+'0');
    	if(ch!='')putchar(ch);
    }
    template<typename T> inline void chkmin(T &x,T y){x=(y<x?y:x);}
    template<typename T> inline void chkmax(T &x,T y){x=(y>x?y:x);}
    template<typename T> inline T min(T x,T y){return x<y?x:y;}
    template<typename T> inline T max(T x,T y){return x>y?x:y;}
    inline void insert(int x,int y,int z,int k)
    {
    	to[++e]=y;
    	nex[e]=beg[x];
    	out[e]=x;
    	beg[x]=e;
    	cap[e]=z;
    	was[e]=k;
    	to[++e]=x;
    	nex[e]=beg[y];
    	out[e]=y;
    	beg[y]=e;
    	cap[e]=0;
    	was[e]=-k;
    }
    inline void Build()
    {
    	e=1;
    	memset(beg,0,sizeof(beg));
    	for(register int i=1;i<=n;++i)
    		for(register int j=1;j<=n;++j)
    			if(~G[i][j])insert(i,j+n,1,-G[i][j]+5001);
    	for(register int i=1;i<=n;++i)insert(s,i,1,0),insert(i+n,t,1,0);
    }
    inline bool bfs()
    {
    	memset(level,inf,sizeof(level));
    	level[s]=0;
    	p[s]=1;
    	q.push(s);
    	while(!q.empty())
    	{
    		int x=q.front();
    		q.pop();
    		p[x]=0;
    		for(register int i=beg[x];i;i=nex[i])
    			if(level[to[i]]>level[x]+was[i]&&cap[i])
    			{
    				level[to[i]]=level[x]+was[i];
    				if(!p[to[i]])p[to[i]]=1,q.push(to[i]);
    			}
    	}
    	return level[t]!=inf;
    }
    inline int dfs(int x,int maxflow)
    {
    	if(x==t||!maxflow)return maxflow;
    	vis[x]=clk;
    	int res=0,f;
    	for(register int &i=cur[x];i;i=nex[i])
    		if((vis[x]^vis[to[i]])&&cap[i]&&level[to[i]]==level[x]+was[i])
    		{
    			f=dfs(to[i],min(maxflow,cap[i]));
    			res+=f;
    			cap[i]-=f;
    			cap[i^1]+=f;
    			maxflow-=f;
    			ans_was+=f*was[i];
    			if(!maxflow)break;
    		}
    	vis[x]=0;
    	return res;
    }
    inline int Dinic()
    {
    	int res=0;
    	ans_was=0;
    	while(bfs())clk++,memcpy(cur,beg,sizeof(cur)),res+=dfs(s,inf);
    	ans_was-=5001*res;
    	return res;
    }
    inline void solve()
    {
    	for(register int i=1,tmp;i<=cnt;++i)
    	{
    		tmp=G[match[i].x][match[i].y];
    		G[match[i].x][match[i].y]=-1;
    		Build();
    		Dinic();
    		if(-ans_was==stand)M[match[i].x][match[i].y]=0;
    		G[match[i].x][match[i].y]=tmp;
    	}
    }
    int main()
    {
    	read(n);
    	for(register int i=1;i<=n;++i)
    		for(register int j=1;j<=n;++j)read(G[i][j]);
    	s=n+n+1,t=s+1;
    	Build();
    	Dinic();
    	stand=-ans_was;
    	write(stand,'
    ');
    	for(register int i=2;i<=n*n*2;i+=2)
    		if(!cap[i])match[++cnt]=(side){out[i],to[i]-n},M[out[i]][to[i]-n]=1;
    	solve();
    	cnt=0;
    	for(register int i=1;i<=n;++i)
    		for(register int j=1;j<=n;++j)
    			if(M[i][j])ans[++cnt]=(side){i,j};
    	std::sort(ans+1,ans+cnt+1);
    	for(register int i=1;i<=cnt;++i)write(ans[i].x,' '),write(ans[i].y,'
    ');
    	return 0;
    }
    
  • 相关阅读:
    更易型算法(Manipulating Algorithms)
    迭代器之配接器
    Windows下BBv2安装编译libtorrent
    swfupload简单使用
    Openx 中文编码解决方案
    常见c语言编译错误解析(转)
    新建一个scrapy项目
    判断两个日期的时间部分之差
    javascript弹出子窗口并返回值
    转:浅析ASP.NET中页面传值的几种方法
  • 原文地址:https://www.cnblogs.com/hongyj/p/9116920.html
Copyright © 2011-2022 走看看