bzoj 1562: [NOI2009]变换序列 匈牙利算法

来源:互联网 发布:网络文化节 编辑:程序博客网 时间:2024/06/11 14:29

题意

这里写图片描述
N≤10000

分析

一个比较显然的二分图匹配模型。一开始想的dinic,但如果要构造字典序最小的话,需要O(n^2)的复杂度。于是就被逼着去又学了一波匈牙利算法。
要字典序最小的话,可以在连边的时候,把边按照终点排序,这样的话每次都是优先找最小的那条边增广。然后我们只要从后往前找增广路,就可以保证字典序最小了。正确性的话自己yy一下即可。

代码

#include<iostream>#include<cstdio>#include<cstdlib>#include<cstring>#include<algorithm>using namespace std;const int N=10005;int n,last[N],pre[N],ans[N],cnt;bool vis[N];struct edge{int to,next;}e[N*2];int read(){    int x=0,f=1;char ch=getchar();    while (ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}    while (ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}    return x*f;}void addedge(int u,int v){    e[++cnt].to=v;e[cnt].next=last[u];last[u]=cnt;}bool find(int x){    for (int i=last[x];i;i=e[i].next)        if (!vis[e[i].to])        {            vis[e[i].to]=1;            if (!pre[e[i].to]||find(pre[e[i].to]))            {                pre[e[i].to]=x;                return 1;            }        }    return 0;}int main(){    n=read();    for (int i=0;i<n;i++)    {        int d=read(),x=(i-d+n)%n,y=(i+d)%n;        if (x<y) swap(x,y);        addedge(i+1,x+1);addedge(i+1,y+1);    }    for (int i=n;i>=1;i--)    {        for (int j=1;j<=n;j++) vis[j]=0;        if (!find(i))        {            puts("No Answer");            return 0;        }    }    for (int i=1;i<=n;i++) ans[pre[i]]=i;    for (int i=1;i<n;i++) printf("%d ",ans[i]-1);    printf("%d",ans[n]-1);    return 0;}