bzoj1562: [NOI2009]变换序列

匈牙利匹配。

在邻接表中每条边以终点升序排序。从x最后一个点往前进行增广,这样每个点首先都能匹配到字典序最小的位置,如果前面的点找不到匹配点时,后面的点就匹配到稍大一点的y匹配点上。

建图说明:每个点有且只会有俩个点符合距离的要求,可以想想为什么。

y点要+n与x点区分开来。

#include<cstdio>
#include<algorithm>
#include<cstring>
#include<vector>
using namespace std;
const int maxn = 30000 + 10;

vector<int> g[maxn];
bool vis[maxn];
int p[maxn];
int n;

bool find(int u) {
    if(vis[u]) return false;
    vis[u]=true;
    
    for(int i=0,v;i<g[u].size();i++) {
        v=g[u][i];
        if(!p[v] || find(p[v])) {
            p[v]=u;
            p[u]=v;
            return true;
        }
    }
    return false;
}


int main() {
    scanf("%d",&n);
    for(int i=0,d;i<n;i++){ 
        scanf("%d",&d);
        int a=(i+d)%n,b=(i+n-d)%n;
        if(a>b) swap(a,b);
        g[i].push_back(a+n);
        g[i].push_back(b+n);    
    }
    for(int i=n-1;i>=0;i--) {
        memset(vis,0,sizeof(vis));
        if(!find(i)) {
            printf("No Answer");
            return 0;    
        }
    }
    for(int i=0;i<n;i++) if(i) printf(" %d",p[i]-n);
    else printf("%d",p[i]-n);
    return 0;
}
posted @ 2016-05-15 09:47  invoid  阅读(120)  评论(0编辑  收藏  举报