bzoj1562【Noi2009】变换序列

题意:http://www.lydsy.com/JudgeOnline/problem.php?id=1562

   给一个序列Di表示min(|i-Ti|,n-|i-Ti|),求一个字典序最小的序列Ti

sol:  对于每个i,能和它连边的只有i+di和(i-di+n)%n

   将图转为二分图,左边为i,右边为Ti,跑匈牙利算法

   为避免数组下标越界、memset-1之类麻烦的问题,右移一位处理

   P.S.行末不能有空格,文末有回车

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
using namespace std;
const int Mx=100010;
int n,tot,Time,tmp,ans[Mx],head[Mx],ver[Mx],next[Mx],vis[Mx],pre[Mx];
void add(int x,int y)
{
    tot++;
    next[tot]=head[x];
    ver[tot]=y;
    head[x]=tot;
}
int dfs(int x)
{
    for(int i=head[x];i;i=next[i])
    {
        int v=ver[i];
        if(vis[v]!=Time)
        {
            vis[v]=Time;
            if(!pre[v]||dfs(pre[v]))
            {
                pre[v]=x,ans[x]=v;
                return 1;
            }
        }
    }
    return 0;
}
int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
    {
        int d,to1,to2; scanf("%d",&d);
        to1=(i+d-1)%n+1,to2=(i-d+n-1)%n+1;
        if(to1<to2) swap(to1,to2);
        add(i,to1); if(to1!=to2) add(i,to2);
    }
    for(int i=n;i;i--) Time++,tmp+=dfs(i);
    if(tmp!=n) puts("No Answer\n");
    else
    {
        for(int i=1;i<n;i++) printf("%d ",ans[i]-1);
        printf("%d\n",ans[n]-1);
    }
    return 0;
}
posted @ 2017-01-15 14:23  Czarina  阅读(139)  评论(0编辑  收藏  举报