BZOJ1562: [NOI2009]变换序列

题目描述##:传送门

题解:

这题显然是二分图完美匹配。然后只要考虑一下字典序最小就好了。

代码如下:

#include<cstdio>
#include<string>
#include<cstring>
using namespace std;
const int maxn=200005;
int n,sum,tot,lnk[maxn],nxt[2*maxn],son[2*maxn],ans[maxn],ans1[maxn],a[5];
bool vis[maxn];
inline int read(){
    int x=0; char ch=getchar();
    while (ch<'0'||ch>'9') ch=getchar();
    while (ch>='0'&&ch<='9') x=x*10+ch-48,ch=getchar();
    return x;
}
void add(int x,int y){son[++tot]=y,nxt[tot]=lnk[x],lnk[x]=tot;}
bool dfs(int x){
    for (int j=lnk[x];j!=-1;j=nxt[j])
    if (!vis[son[j]]) {
        vis[son[j]]=1;
        if (ans[son[j]]==-1||dfs(ans[son[j]])) {ans[son[j]]=x,ans1[x]=son[j]; return 1;}
    }
    return 0;
}
int main(){
    n=read();
    memset(ans,-1,sizeof(ans));
    memset(ans1,-1,sizeof(ans1));
    memset(lnk,-1,sizeof(lnk));
    for (int i=0;i<n;i++) {
        int x=read();
        a[1]=i-x,a[2]=i+x;
        if (a[1]<0) a[1]+=n; if (a[2]>=n) a[2]=a[2]%n;
        if (a[1]<a[2]) swap(a[1],a[2]);
        add(i,a[1]); add(i,a[2]);
    }
    for (int i=n-1;i>=0;i--) {memset(vis,0,sizeof(vis)); if (dfs(i)) sum++; else break;}
    if (sum!=n) printf("No Answer\n"); else 
    for (int i=0;i<n;i++) printf("%d ",ans1[i]);
    return 0;
}

猜你喜欢

转载自blog.csdn.net/dyt_b/article/details/79943608