[NOI2009]变换序列(二分图完美匹配)

【题解】

容易想到:在X集中的每个点i与满足dis(i,j)==D[i]的Y集中的点j间连一条边,这样构成了一张二分图 
那么题目转化为:
二分图是否存在完美匹配?
·否:No Answer
·是:记 1,2,…,n 的匹配点为 T[1],T[2],…,T[n],输出一组字典序最小的 T[1],T[2],…,T[n]

在匈牙利算法中:
扩展增广路的过程中,那些匹配点改变的点都是已经匹配上的点(以下称为:"已覆盖点"),
而那个当前正在寻找匹配的点,能够通过增广的方式,改变其它"已覆盖点"的匹配点,从而保证自己的匹配点编号最小 

因此,在执行匈牙利算法时,只需倒着枚举X集中要匹配的点即可 


【代码】

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<vector>
using namespace std;
vector<int> G[10005];
int left[10005],right[10005],y[10005];
void jh(int* a,int* b)
{
	int t=*a;
	*a=*b;
	*b=t;
}
int find(int u)
{
	int i,v;
	for(i=0;i<=1;i++)
	{
		v=G[u][i];
		if(y[v]==1) continue;
		y[v]=1;
		if(left[v]==-1||find(left[v])==1)
		{
			left[v]=u;
			return 1;
		}
	}
	return 0;
}
int main()
{
	int n,i,d;
	scanf("%d",&n);
	for(i=0;i<n;i++)
	{
		scanf("%d",&d);
		if(i-d>=0&&i-d<n) G[i].push_back(i-d);
		if(i+d>=0&&i+d<n) G[i].push_back(i+d);
		if(i+n-d>=0&&i+n-d<n) G[i].push_back(i+n-d);
		if(i-n+d>=0&&i-n+d<n) G[i].push_back(i-n+d);
		if(G[i][0]>G[i][1]) jh(&G[i][0],&G[i][1]);
	}
	for(i=0;i<n;i++)
		left[i]=-1;
	for(i=n-1;i>=0;i--)
	{
		memset(y,0,sizeof(y));
		if(find(i)==0) break;
	} 
	if(i>=0) printf("No Answer");
	else
	{
		for(i=0;i<n;i++)
			right[left[i]]=i;
		for(i=0;i<n;i++)
		{
			if(i>0) printf(" ");
			printf("%d",right[i]);
		}
	}
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值