【网络流】[Codeforces - 739D]Recover a functional graph

题目大意

有一个n个点的有向图,每个点的出度为1。
对于每个点,有两个信息,一个是这个点到环的距离x,一个是这个点能够到达的环的长度y。
有一些点的的某些信息未知,求能否构造出这样一个图。

分析

对于两个信息都已经知道的点,我们就可以根据这些点来算出我们还需要哪些点。
那些有部分信息未知的点就可以向需求连边,跑网络流。
如果所有需求都能被满足,则有解。
特别地,对于y未知的点,如果它的x大于了y已知的点的最大的x,那他的y的取值就需要枚举。
最后根据网络流的结果构造答案。

代码

#include<cstdio>
#include<queue>
#include<cstring>
#include<algorithm>
#define MAXN 300
#define INF 0x7fffffff
using namespace std;
queue<int>q;
template<class T>
void Read(T &x){
    char c;
    bool f(0);
    while(c=getchar(),c!=EOF)
        if(c=='-')
            f=1;
        else if(c=='?'){
            x=-1;
            return;
        }
        else if(c>='0'&&c<='9'){
            x=c-'0';
            while(c=getchar(),c>='0'&&c<='9')
                x=x*10+c-'0';
            ungetc(c,stdin);
            if(f)
                x=-x;
            return;
        }
}
struct node{
    int v,cap;
    node *next,*back;
}*adj[MAXN*3+10],edge[MAXN*MAXN*10+10],*ecnt=edge;
inline void addedge(int u,int v,int cap){
    node *p=++ecnt;
    p->v=v;
    p->next=adj[u];
    p->cap=cap;
    adj[u]=p;
    p=p->back=++ecnt;
    p->v=u;
    p->next=adj[v];
    p->cap=0;
    adj[v]=p;
    p->back=ecnt-1;
}
int tot,dist[MAXN*3+10],vd[MAXN*3+10],n,nxt[MAXN+10],mxx,now,x[MAXN+10],y[MAXN+10],vis[MAXN+10][MAXN+10],S,T;
typedef pair<int,int>pii;
pii b[MAXN*3+10];
vector<int>incir[MAXN+10];
bool flag=0,ex[MAXN+10];
void read(){
    Read(n);
    int i;
    for(i=1;i<=n;i++){
        Read(x[i]),Read(y[i]);
        if(~y[i]){
            ex[y[i]]=1;
            flag=1;
            mxx=max(mxx,x[i]);
            if(!x[i]){
                vis[x[i]][y[i]]=i;
                incir[y[i]].push_back(i);
            }
            else if(x[i]>0)
                vis[x[i]][y[i]]=i;
        }
    }
}
void spfa(int S){
    bool vis[MAXN*3+10]={0};
    int i,u;
    for(i=1;i<=tot;i++)
        dist[i]=INF;
    dist[S]=0;
    q.push(S);
    while(!q.empty()){
        u=q.front();
        q.pop();
        vis[u]=0;
        for(node *p=adj[u];p;p=p->next)
            if(p->back->cap&&dist[p->v]>dist[u]+1){
                dist[p->v]=dist[u]+1;
                if(!vis[p->v])
                    q.push(p->v),vis[p->v]=1;
            }
    }
}
int dfs(int u,int augu){
    if(u==T)
        return augu;
    int augv=0,delta,mind=tot-1;
    for(node *p=adj[u];p;p=p->next)
        if(p->cap){
            if(dist[u]==dist[p->v]+1){
                delta=min(p->cap,augu-augv);
                delta=dfs(p->v,delta);
                p->cap-=delta;
                p->back->cap+=delta;
                augv+=delta;
                if(dist[S]>=tot||augv==augu)
                    return augv;
            }
            mind=min(mind,dist[p->v]);
        }
    if(!augv){
        if(!--vd[dist[u]])
            dist[S]=tot;
        vd[dist[u]=mind+1]++;
    }
    return augv;
}
int sap(){
    spfa(T);
    int i,flow=0;
    for(i=1;i<=tot;i++)
        vd[i]=0;
    for(i=1;i<=tot;i++)
        if(dist[i]<INF)
            vd[dist[i]]++;
    while(dist[S]<tot){
        flow+=dfs(S,INF);
    }
    return flow;
}
void print(){
    int i,j;
    for(i=1;i<=n;i++){
        if(x[i]<=mxx&&(x[i]==-1||y[i]==-1))
            for(node *p=adj[i];p;p=p->next)
                if(p->v>n&&p->v!=S&&p->v!=T&&!p->cap){
                    if(p->v<=2*n){
                        incir[p->v-n].push_back(i);
                        x[i]=0,y[i]=p->v-n;
                        vis[x[i]][y[i]]=i;
                    }
                    else{
                        vis[b[p->v].second][b[p->v].first]=i;
                        x[i]=b[p->v].second,y[i]=b[p->v].first;
                    }
                    break;
                }
    }
    for(i=1;i<=n;i++){
        for(j=0;j<incir[i].size();j++)
            if(j%i==i-1)
                nxt[incir[i][j]]=incir[i][j-i+1];
            else
                nxt[incir[i][j]]=incir[i][j+1];
    }
    for(i=1;i<=n;i++){
        if(x[i]==-1&&y[i]==-1)
            nxt[i]=i;
        else if(x[i]==-1)
            x[i]=1;
        else if(y[i]==-1){
            if(!x[i])
                y[i]=1,nxt[i]=i;
            else
                for(j=1;j<=n;j++)
                    if(vis[x[i]-1][j]){
                        y[i]=j;
                        break;
                    }
        }
        if(!nxt[i])
            nxt[i]=vis[x[i]-1][y[i]];
        printf("%d ",nxt[i]);
    }
}
bool check(){
    memset(adj,0,sizeof adj);
    ecnt=edge;
    S=n*2+1,T=tot=S+1;
    int i,cnt=0,need=0,j,k;
    for(i=1;i<=n;i++)
        if(x[i]<=mxx&&(x[i]==-1||y[i]==-1)){
            addedge(S,i,1);
            cnt++;
        }
    for(i=1;i<=n;i++){
        if(ex[i]){
            if(!incir[i].size()||incir[i].size()%i){
                addedge(i+n,T,i-incir[i].size()%i);
                need+=i-incir[i].size()%i;
                if(need>cnt)
                    return 0;
                for(j=1;j<=n;j++)
                    if((x[j]==-1&&y[j]==-1)||(x[j]==-1&&y[j]==i)||(x[j]==0&&y[j]==-1))
                        addedge(j,n+i,1);
            }
            for(j=n;j&&!vis[j][i];j--);
            for(;j;j--){
                if(!vis[j][i]){
                    b[++tot]=pii(i,j);
                    need++;
                    if(need>cnt)
                        return 0;
                    addedge(tot,T,1);
                    for(k=1;k<=n;k++)
                        if((x[k]==-1&&y[k]==-1)||(x[k]==-1&&y[k]==i)||(x[k]==j&&y[k]==-1))
                            addedge(k,tot,1);
                }
            }
        }
    }
    if(sap()<need)
        return 0;
    print();
    return 1;
}
void solve(){
    int i,j;
    if(flag){
        for(i=1;i<=n;i++)
            if(ex[i]){
                now=i;
                for(j=1;j<=n;j++)
                    if(x[j]>mxx)
                        vis[x[j]][i]=j,y[j]=i;
                if(check())
                    return;
                for(j=1;j<=n;j++)
                    if(x[j]>mxx)
                        vis[x[j]][i]=0;
            }
    }
    else{
        ex[1]=1;
        for(i=1;i<=n;i++)
            if(~x[i])
                vis[x[i]][1]=i;
            if(check())
                return;
    }
    puts("-1");
}
int main()
{
    read();
    solve();
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值