题意: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 "); else { for(int i=1;i<n;i++) printf("%d ",ans[i]-1); printf("%d ",ans[n]-1); } return 0; }