bzoj1562 [NOI2009]变换序列(二分图完美匹配+贪心)

来源:互联网 发布:gta5低配优化补丁 编辑:程序博客网 时间:2024/04/29 20:08

可以发现,每个数最多可以变成两个数,我们以此为边建二分图。然后跑完美匹配即可。题目还要求输出字典序最小的答案,这个怎么做呢?考虑我们匈牙利算法的过程,如果强制要求每个点先连向小的,再连向大的,则我们会尝试着先给当前数匹配小的,而之前匹配过的数要为他腾位置,因此我们只要倒着匹配就好啦!让最后匹配的尽量小。
严谨的证明见dalao byvoid:https://www.byvoid.com/zhs/blog/noi-2009-transform
%%%

#include <bits/stdc++.h>using namespace std;#define N 10010#define ll long long#define inf 0x3f3f3f3finline 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;}int n,bf[N],gf[N];bool f[N];vector<int>e[N];bool find(int x){    for(int i=0;i<e[x].size();++i){        int y=e[x][i];if(f[y]) continue;f[y]=1;        if(!bf[y]||find(bf[y])){            bf[y]=x;gf[x]=y;return 1;        }    }return 0;}int main(){//  freopen("a.in","r",stdin);    n=read();    for(int i=1;i<=n;++i){        int x=read(),x1,x2;        if(i-x>=1) x1=i-x;else x1=i-x+n;        if(x*2==n){e[i].push_back(x1);continue;}        if(i+x<=n) x2=i+x;else x2=i+x-n;        if(x1>x2) swap(x1,x2);e[i].push_back(x1);e[i].push_back(x2);    }    for(int i=n;i>=1;--i){        memset(f,0,sizeof(f));if(!find(i)){puts("No Answer");return 0;}    }    for(int i=1;i<n;++i) printf("%d ",gf[i]-1);printf("%d\n",gf[n]-1);    return 0;}
原创粉丝点击