CF739D Recover a functional graph
Link
首先把所有的按环长分类,那么我们需要做的就是满足以下几个条件:
\(1.\)每个环长的到环距离为\(0\)的点的个数应该是环长的倍数。当然只需要在最低限度下将其补齐即可。
\(2.\)每个环长的到环距离必须是连续的。
\(3.\)必须要有某个环去接受环长为\(?\)的距离最长的点。
那么我们可以枚举把环长为\(?\)的距离最长的点放在哪个长度的环,然后二分图匹配补齐\(1,2\)两条限制,多余出的点随便搞搞就完事了。
#include<cstdio>
#include<vector>
#include<cstdlib>
#include<cstring>
const int N=307;
int max(int a,int b){return a>b? a:b;}
int n,m,mx,len[N],dis[N],fa[N],x[N],y[N],cnt[N],mxd[N],e[N][N],vis[N],L[N],R[N],mat[N];
std::vector<int>vec[N];char s1[5],s2[5];
int dfs(int u)
{
for(int v=1;v<=m;++v) if(e[u][v]&&!vis[v]&&!R[v]) if(vis[v]=1,!mat[v]||dfs(mat[v])) return mat[v]=u,1;
return 0;
}
int check(int p)
{
memset(e,0,sizeof e),memset(L,0,sizeof L),memset(R,0,sizeof R),memset(mat,0,sizeof mat),m=0;
for(int i=1;i<=n;++i)
if(~mxd[i]||i==p)
{
int c=cnt[i],l=mxd[i];
if(i==p) c=max(c,i),l=max(l,mx);
for(int j=1;j<=c;++j)
{
if(++m>n) return 0;
x[m]=i,y[m]=0;
}
for(int j=1;j<=l;j++)
{
if(++m>n) return 0;
x[m]=i,y[m]=j;
}
}
int ans=0;
for(int i=1;i<=n;++i)
for(int j=1;j<=m;++j)
{
e[i][j]=(len[i]==x[j]||!~len[i])&&(dis[i]==y[j]||!~dis[i]);
if(len[i]==x[j]&&dis[i]==y[j]&&!L[i]&&!R[j]) L[i]=R[j]=1,mat[j]=i,++ans;
}
for(int i=1;i<=n;++i) if(!L[i]) memset(vis,0,sizeof vis),ans+=dfs(i);
return ans==m;
}
void print(int p)
{
for(int i=1;i<=m;++i) len[mat[i]]=x[i],dis[mat[i]]=y[i];
for(int i=1;i<=n;++i)
if(!~len[i]) if(dis[i]<=0) dis[i]=0,len[i]=1; else len[i]=p;
else if(!~dis[i]) dis[i]=1;
for(int i=1;i<=n;++i) for(int j=1;j<=n;++j) if(len[i]==len[j]&&dis[i]==dis[j]+1) {fa[i]=j;break;}
for(int i=1;i<=n;++i)
if(!dis[i])
{
vec[len[i]].push_back(i);
if((int)vec[len[i]].size()==len[i])
{
for(int j=0;j<len[i];++j) fa[vec[len[i]][j]]=vec[len[i]][(j+1)%len[i]];
vec[len[i]].clear();
}
}
for(int i=1;i<=n;++i) printf("%d ",fa[i]);
}
int main()
{
scanf("%d",&n),memset(mxd,-1,sizeof mxd);
for(int i=1;i<=n;++i)
{
scanf("%s%s",s1,s2),dis[i]=s1[0]=='?'? -1:std::atoi(s1),len[i]=s2[0]=='?'? -1:std::atoi(s2);
if(~len[i])
{
mxd[len[i]]=max(mxd[len[i]],max(dis[i],0));
if(!dis[i]) ++cnt[len[i]];
}
else mx=max(mx,dis[i]);
}
for(int i=1;i<=n;++i) cnt[i]=max(1,(cnt[i]+i-1)/i)*i;
for(int i=1;i<=n;++i) if(check(i)) return print(i),0;
puts("-1");
}