【题解】
容易想到:在X集中的每个点i与满足dis(i,j)==D[i]的Y集中的点j间连一条边,这样构成了一张二分图
那么题目转化为:
二分图是否存在完美匹配?
·否:No Answer
·是:记 1,2,…,n 的匹配点为 T[1],T[2],…,T[n],输出一组字典序最小的 T[1],T[2],…,T[n]
在匈牙利算法中:
扩展增广路的过程中,那些匹配点改变的点都是已经匹配上的点(以下称为:"已覆盖点"),
而那个当前正在寻找匹配的点,能够通过增广的方式,改变其它"已覆盖点"的匹配点,从而保证自己的匹配点编号最小
因此,在执行匈牙利算法时,只需倒着枚举X集中要匹配的点即可
【代码】
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<vector>
using namespace std;
vector<int> G[10005];
int left[10005],right[10005],y[10005];
void jh(int* a,int* b)
{
int t=*a;
*a=*b;
*b=t;
}
int find(int u)
{
int i,v;
for(i=0;i<=1;i++)
{
v=G[u][i];
if(y[v]==1) continue;
y[v]=1;
if(left[v]==-1||find(left[v])==1)
{
left[v]=u;
return 1;
}
}
return 0;
}
int main()
{
int n,i,d;
scanf("%d",&n);
for(i=0;i<n;i++)
{
scanf("%d",&d);
if(i-d>=0&&i-d<n) G[i].push_back(i-d);
if(i+d>=0&&i+d<n) G[i].push_back(i+d);
if(i+n-d>=0&&i+n-d<n) G[i].push_back(i+n-d);
if(i-n+d>=0&&i-n+d<n) G[i].push_back(i-n+d);
if(G[i][0]>G[i][1]) jh(&G[i][0],&G[i][1]);
}
for(i=0;i<n;i++)
left[i]=-1;
for(i=n-1;i>=0;i--)
{
memset(y,0,sizeof(y));
if(find(i)==0) break;
}
if(i>=0) printf("No Answer");
else
{
for(i=0;i<n;i++)
right[left[i]]=i;
for(i=0;i<n;i++)
{
if(i>0) printf(" ");
printf("%d",right[i]);
}
}
return 0;
}