题目大意
给定对于一个1至
要求还原这个排列。
方案可能很多,输出一种即可。如果没有符合要求的排列,则输出-1。
1≤n≤200,0≤m≤40000
题目分析
有“约束条件“,再看到n在
我们发现,约束1就是限定区间[x..y]必须有v这个数,且所有数字小于等于
那么我们应该仔细考虑一下如何确定每个位置能取哪些数。比赛时我由于太急躁,并没有想好这个条件。
我们归纳总结可以发现,位置i能放
我们通过枚举约束求出每个位置最大能放几,最小能放几,同时求出每个数是否出现在不包含该位置的约束中。然后位置向能连的数连边,做匈牙利匹配即可。
时间复杂度O(n3)。
代码实现
#include <iostream>
#include <cstring>
#include <cstdio>
#include <cmath>
using namespace std;
const int N=200;
const int M=40000;
struct constraint
{
int kind,l,r,x;
}c[M+1];
int next[N*N+1],tov[N*N+1];
int belong[N+1],last[N+1];
bool vis[N+1],num[N+1],r[N+1];
int n,m,can,tot;
int read()
{
int x=0,f=1;
char ch=getchar();
while (ch<'0'||ch>'9')
{
if (ch=='-')
f=-1;
ch=getchar();
}
while (ch>='0'&&ch<='9')
{
x=x*10+ch-'0';
ch=getchar();
}
return x*f;
}
void insert(int x,int y)
{
tov[++tot]=y;
next[tot]=last[x];
last[x]=tot;
}
bool hungary(int x)
{
int i=last[x],y;
vis[x]=true;
while (i)
{
y=tov[i];
if (!belong[y]||!vis[belong[y]]&&hungary(belong[y]))
{
belong[y]=x;
return true;
}
i=next[i];
}
return false;
}
bool cmp(constraint x,constraint y)
{
return x.l<y.l;
}
int main()
{
freopen("arrangement.in","r",stdin);
freopen("arrangement.out","w",stdout);
n=read(),m=read();
for (int i=1;i<=m;i++)
c[i].kind=read(),c[i].l=read(),c[i].r=read(),c[i].x=read();
int mins,maxs;
for (int i=1;i<=n;i++)
{
memset(r,false,sizeof r);
mins=1,maxs=n;
for (int j=1;j<=m;j++)
if (c[j].l<=i&&i<=c[j].r)
if (c[j].kind==1)
maxs=min(maxs,c[j].x);
else
mins=max(mins,c[j].x);
else
r[c[j].x]=true;
mins=max(mins,1);
maxs=min(maxs,n);
for (int j=mins;j<=maxs;j++)
if (!num[j]&&!r[j])
insert(i,j);
}
for (int i=1;i<=n;i++)
{
memset(vis,false,sizeof vis);
if (hungary(i))
can++;
}
if (can<n)
printf("-1");
else
{
for (int i=1;i<=n;i++)
last[belong[i]]=i;
for (int i=1;i<n;i++)
printf("%d ",last[i]);
printf("%d\n",last[n]);
}
fclose(stdin);
fclose(stdout);
return 0;
}