JZOJ 3163. 【GDOI2013模拟2】排列(二分图匹配)

JZOJ 3163. 【GDOI2013模拟2】排列

题目

Description

给你 M M M个对 1 1 1 N N N的排列的特征,特征有两种:

1 1 1 x x x y y y v v v:排列的第 x x x个数到第 y y y个数之间的最大值为 v v v

2 2 2 x x x y y y v v v:排列的第 x x x个数到第 y y y个数之间的最小值为 v v v.

要求你还原出这个排列。

Input

第一行输入两个整数 N ( 1 ≤ N ≤ 200 ) N(1≤N≤200) N(1N200) M ( 0 ≤ M ≤ 40 , 000 ) M(0≤M≤40,000) M(0M40,000) N N N表示排列的数字个数, M M M表示特征数量。

接下来 M M M行,每行描述一个特征。

Output

输出一行,满足所有特征的 1 1 1 N N N的一个排列。方案可能有很多,输出其中一个即可。如果无解,输出 − 1 -1 1

Sample Input

输入1:
3 2
1 1 1 1
2 2 2 2

输入2:
4 2
1 1 1 1
2 3 4 1

输入3:
5 2
1 2 3 3
2 4 5 4

Sample Output

输出1:
1 2 3

输出2:
-1

输出3:
1 2 3 4 5

Data Constraint

100%的数据满足 N ( 1 ≤ N ≤ 200 ) , M ( 0 ≤ M ≤ 40 , 000 ) N(1≤N≤200),M(0≤M≤40,000) N(1N200)M(0M40,000).

题解

  • 由题目可知,最终的序列是 1 1 1 N N N的排列,数字没有重复,不难想到二分图匹配!
  • 怎么连边?
  • 根据题目的要求,可以得到每个位置的数字的上下界,全部连上一条边(最初的上下界为 [ 1 , N ] [1,N] [1,N])。
  • 但是,即使每个位置上的数都符合上下界的要求,但也不一定满足 M M M个区间的最大/最小值的要求。
  • 为什么?
  • 某区间中的数,假若它们上下界均为 [ l , r ] [l,r] [l,r],且要求该区间最小值为 l l l
  • 但如果直接跑一遍匈牙利算法,得到的这个区间所选的数不一定包含 l l l(因为还有其它选择),
  • 以至于这个区间的最小值不是要求的 l l l
  • 所以,光判断上下界是不行的!!!
  • 怎么修改?
  • 很简单,若某区间的最大/最小值为 x x x,则必须保证这个区间中的某个数向 x x x连了一条边,否则不符合题意,
  • 为了保证这样,就把该区间外的位置向 x x x连的边全部删除。
  • 如此以来,如果最终能跑出来,那么一定是符合每个区间的要求的。

代码

#include<cstdio>
#include<cstring>
using namespace std;
struct
{
	int a,l,r,s;
}a[40010];
int bz[210],c[210],d[210];
int e[210][210],n;
int dfs(int k)
{
	for(int i=1;i<=n;i++) if(e[k][i]&&!bz[i])
	{
		bz[i]=1;
		if(d[i]==0||dfs(d[i]))
		{
			d[i]=k;
			c[k]=i;
			return 1;
		}
	}
	return 0;
}
int main()
{
	int m,i,j;
	scanf("%d%d",&n,&m);
	for(i=1;i<=m;i++) scanf("%d%d%d%d",&a[i].a,&a[i].l,&a[i].r,&a[i].s);	
	for(i=1;i<=n;i++)
	{
		int l=1,r=n;
		for(j=1;j<=m;j++) 
		{
			if(a[j].a==1&&i>=a[j].l&&i<=a[j].r&&a[j].s<r) r=a[j].s;
			if(a[j].a==2&&i>=a[j].l&&i<=a[j].r&&a[j].s>l) l=a[j].s;
		}
		for(j=l;j<=r;j++) e[i][j]=1;
	}
	for(i=1;i<=m;i++)
	{
		for(j=1;j<=n;j++) if(j<a[i].l||j>a[i].r) e[j][a[i].s]=0;
	}
	int s=0;
	for(i=1;i<=n;i++) 
	{
		memset(bz,0,sizeof(bz));
		if(dfs(i)) s++;
	}
	if(s<n) 
	{
		printf("-1");
		return 0;
	}
	for(i=1;i<=n;i++) printf("%d ",c[i]);
	return 0;
}
哈哈哈哈哈哈哈哈哈哈
原文地址:https://www.cnblogs.com/LZA119/p/13910086.html