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");
}
posted @ 2020-01-27 21:57  Shiina_Mashiro  阅读(245)  评论(1编辑  收藏  举报