距离序列(匈牙利算法+最小字典序)

刚开始用暴力打出每个数字相匹配的那个数字。然后就是运用匈牙利算法进行计算,但是得字典序输出。所以采用倒着使用匈牙利算法。同时存储图的时候由于最大是1000,所以采用vector的邻接表进行存储。

ac代码:(900ms)

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<string>
#include<map>
#include<vector>
#include<cmath>
#include<cstdlib>
#include<list>
#include<queue>
#define mm(a,b) memset(a,b,sizeof(a))
#define ACCELERATE (ios::sync_with_stdio(false),cin.tie(0))
typedef long long ll;
typedef long double ld;
typedef unsigned long long ull;
#define MAXN 0x3f3f3f3f3f3f3f3f
#define PI acos(-1.0)
#define E exp(1.0)
using namespace std;

//#define debug

const int maxn=10005;

vector<int> e[maxn];
int vis[maxn];
int boy[maxn];
int a[maxn];
int gril[maxn];

int n;

bool dfs(int v){
    for(int i=0;i<n;i++){
        if(!vis[i]&&count(e[v].begin(),e[v].end(),i)){
            vis[i]=1;
            if(boy[i]==-1||dfs(boy[i])){
                boy[i]=v;
                gril[v]=i;
                return 1;
            }
        }
    }
    return 0;
}

int main()
{
    #ifdef debug
    freopen("in.txt","r",stdin);
    freopen("out.txt","w",stdout);
    #endif // debug
    
    ACCELERATE;
    cin>>n;
    for(int i=0;i<n;i++){
        cin>>a[i];
    }
    for(int i=0;i<n;i++){
        for(int j=0;j<n;j++){
            if(min(abs(i-j),n-abs(i-j))==a[i]){
                e[i].push_back(j);
            }
        }
    }
    mm(vis,0);
    mm(boy,-1);
    int tot=0;
    for(int i=n-1;i>=0;i--){
        mm(vis,0);
        if(dfs(i)) tot++;
    }
    if(tot!=n){
        printf("No Answer\n");
    }
    for(int i=0;i<n-1;i++){
        cout<<gril[i]<<" ";
    }
    cout<<gril[n-1]<<endl;
    return 0;
}

还有一种就是运用嗯二分图匹配,刚开始配对的是i跟j+n,还有j+n跟i,因为匈牙利算法计算的匹配是后面跟前,而现在转为前面跟后面,所以+n这种配对方式有很大优势,而在dfs里面,右边匹配左边先标记的左边,所以左边匹配右边就先标记右边。 同时得用vis判断一下是否会造成循环。因为是两端一起匹配。

ac代码:(200ms)

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<string>
#include<map>
#include<vector>
#include<cmath>
#include<cstdlib>
#include<list>
#include<queue>
#define mm(a,b) memset(a,b,sizeof(a))
#define ACCELERATE (ios::sync_with_stdio(false),cin.tie(0))
typedef long long ll;
typedef long double ld;
typedef unsigned long long ull;
#define MAXN 0x3f3f3f3f3f3f3f3f
#define PI acos(-1.0)
#define E exp(1.0)
using namespace std;

//#define debug

const int maxn=10005;

vector<int> e[maxn*2];
int vis[maxn*2];
int match[maxn*2];
int a[maxn*2];

int n;

bool dfs(int v){
    vis[v]=1;
    for(int i=0;i<e[v].size();i++){
        int u=e[v][i],w=match[u];
        //printf("%d   %d   %d   %d   %d-----\n",v,u,w,vis[w],match[w]);
        if(w==-1||!vis[w]&&dfs(match[u])){      //!vis[w] 的意思是因为两端都在匹配,防止造成循环匹配到下面,又匹配到上边。 
            match[u]=v;
            match[v]=u;
            return 1;
        }
    }
    return 0;
}

int main()
{
    #ifdef debug
    freopen("in.txt","r",stdin);
    freopen("out.txt","w",stdout);
    #endif // debug

    cin>>n;
    for(int i=0;i<n;i++){
        cin>>a[i];
    }
    for(int i=0;i<2*n;i++){
        e[i].clear();
    }
    for(int i=0;i<n;i++){
        for(int j=0;j<n;j++){
            if(min(abs(i-j),n-abs(i-j))==a[i]){
                e[i].push_back(j+n);
                e[j+n].push_back(i);
            }
        }
    }
    mm(vis,0);
    mm(match,-1);
    for(int i=0;i<n;i++){
        sort(e[i].begin(),e[i].end());
    }
    int tot=0;
    for(int i=n-1;i>=0;i--){
        mm(vis,0);
        if(dfs(i)) tot++;
    }
    if(tot!=n){
        printf("No Answer\n");
    }
    for(int i=0;i<n-1;i++){
        printf("%d ",match[i]-n);
    }
    cout<<match[n-1]-n<<endl;
    return 0;
}
/*
10
1 5 4 2 3 1 4 3 1 4
1 6 8 5 7 4 2 0 9 3
*/

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值