BZOJ1562: [NOI2009]变换序列(匈牙利算法,字典序相关)

来源:互联网 发布:linux系统zip命令 编辑:程序博客网 时间:2024/05/16 16:57

传送门

题意:

对于0,1,,N1N个整数,给定一个距离序列D0,D1,,DN1,定义一个变换序列T0,T1,,TN1使得每个i,Ti的环上距离等于Di。一个合法的变换序列应是0,1,,N1的一个排列,任务是要求出字典序最小的那个变换序列。

题解:

一个合法的变换序列是一个完备匹配。那么先随便找一个完备匹配,再从前往后贪心选取边判断是否能重新构成完备匹配即可。时间复杂度O(n2)

#include<bits/stdc++.h>using namespace std;inline int rd(){    char ch=getchar();int i=0,f=1;    while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}    while(isdigit(ch)){i=(i<<1)+(i<<3)+ch-'0';ch=getchar();}    return i*f;}const int Maxn=2e4+50;int n,ban[Maxn],mate[Maxn],vis[Maxn],vt;vector<int>v[Maxn];inline bool Hungry(int x){    vis[x]=vt;    for(int j=0;j<v[x].size();++j){        int t=v[x][j];        if(ban[t]||(mate[t]!=-1&&vis[mate[t]]==vt))continue;        if(mate[t]==-1||Hungry(mate[t]))return mate[x]=t,mate[t]=x,true;    }    return false;}int main(){    n=rd();memset(mate,-1,sizeof(mate));    for(int i=0;i<n;i++){        int d=rd(),x1=(i+d)%n,x2=(i-d+n)%n;        v[i].push_back(x1+n);v[x1+n].push_back(i);        if(x1!=x2)v[i].push_back(x2+n),v[x2+n].push_back(i);    }    for(int i=2*n-1;i>=0;i--)sort(v[i].begin(),v[i].end());    for(int i=0;i<n;i++){        if(!(++vt,Hungry(i))){printf("No Answer");return 0;}    }    for(int i=0;i<n;i++){        mate[mate[i]]=-1,mate[i]=-1;        ++vt,Hungry(i);        ban[i]=1;ban[mate[i]]=1;    }    for(int i=0;i<n-1;i++)printf("%d ",mate[i]-n);    printf("%d",mate[n-1]-n);}
原创粉丝点击