BZOJ1562 NOI2009 变换序列 二分图

题意:给定一个由1-N不重复组成的序列a,再给出N个数的序列b,求是否存在一个序列c,使得任意一个位置i均满足(ai+bi)%N=ci || (ai-bi+N)%N=ci,并求字典序最小的c

题解:

任意一个ai只能变成两个数,所以我们可以建二分图看是否存在完全匹配来确定是否存在合法序列。

由于方案要求字典序最小,因此开邻接表的时候要越小的越在前面,匹配时从N开始匹配。这个比较显然,因为越早匹配完成,之后的点如果产生冲突,一定是先完成匹配的点的匹配点变大。

#include <queue>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <algorithm>
using namespace std;

const int MAXN=20000+2;
const int MAXM=40000+2;
struct HASH{
    int u;
    HASH *next;
    HASH(){}
    HASH(int _u,HASH *_next):u(_u),next(_next){}
}*table[MAXN],mem[MAXM];
int N,cnt,markx[MAXN],marky[MAXN];
bool flag[MAXN];

void Insert(int u,int v){ table[u]=&(mem[cnt++]=HASH(v,table[u]));}

bool DFS(int x){
    for(HASH *p=table[x];p;p=p->next)
        if(!flag[p->u]){
            flag[p->u]=1;
            if(marky[p->u]==-1 || DFS(marky[p->u])){
                markx[x]=p->u,marky[p->u]=x;
                return 1;
            }
        }
    return 0;
}

void Hungary(){
    memset(marky,-1,sizeof(marky));
    for(int i=N-1;i>=0;i--){
        memset(flag,0,sizeof(flag));
        if(!DFS(i)){
            cout << "No Answer" << endl;
            exit(0);
        }
    }
}

int main(){
    cin >> N;
    for(int i=1,a,b,D;i<=N;i++){
        cin >> D;
        a=(i-1+D)%N,b=(i-1-D+N)%N;
        if(a>b) swap(a,b);
        Insert(i-1,N+b),Insert(i-1,N+a);
    }

    Hungary();
    for(int i=0;i<N;i++) cout << markx[i]-N << " ";
    cout << endl;

    return 0;
}
View Code

 

posted @ 2017-02-28 21:57  WDZRMPCBIT  阅读(122)  评论(0编辑  收藏  举报