BZOJ 1562 [NOI2009]变换序列:二分图匹配

题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=1562

题意:

  给定n,定义D(x,y) =  min(|x-y|, n-|x-y|),然后给定数组d[i] = D(i,T[i])。

  让你求一个0到n-1的排列T,下标i∈[0,n-1],满足给定的D(i,T[i]),且字典序最小。

  若没有答案输出"No Answer"。

题解:

  其实就是让你求一个排列T,其中T[i]要么填(i+d[i])%n,要么填(i-d[i]+n)%n。

  所以对于每个i,向它能填的两个数连边,跑一边最大匹配即可。

  又因为要求字典序最小,所以对于每个i连边时,应先连向较小的那个数。然后跑匈牙利的时候按从n-1到0的顺序跑即可。

AC Code:

 1 #include <iostream>
 2 #include <stdio.h>
 3 #include <string.h>
 4 #include <vector>
 5 #define MAX_N 10005
 6 
 7 using namespace std;
 8 
 9 int n;
10 int d[MAX_N];
11 int vis[MAX_N];
12 int mat[MAX_N];
13 int rmat[MAX_N];
14 int edge[MAX_N][2];
15 
16 bool hungary(int now,int cnt)
17 {
18     for(int i=0;i<2;i++)
19     {
20         int temp=edge[now][i];
21         if(vis[temp]!=cnt)
22         {
23             vis[temp]=cnt;
24             if(mat[temp]==-1 || hungary(mat[temp],cnt))
25             {
26                 mat[temp]=now;
27                 rmat[now]=temp;
28                 return true;
29             }
30         }
31     }
32     return false;
33 }
34 
35 int main()
36 {
37     cin>>n;
38     for(int i=0;i<n;i++)
39     {
40         cin>>d[i];
41         if(d[i]>n/2)
42         {
43             cout<<"No Answer"<<endl;
44             return 0;
45         }
46         int x=(i+d[i])%n;
47         int y=(i-d[i]+n)%n;
48         edge[i][0]=min(x,y);
49         edge[i][1]=max(x,y);
50     }
51     memset(vis,0,sizeof(vis));
52     memset(mat,-1,sizeof(mat));
53     for(int i=n-1;i>=0;i--)
54     {
55         if(!hungary(i,i+1))
56         {
57             cout<<"No Answer"<<endl;
58             return 0;
59         }
60     }
61     for(int i=0;i<n;i++) cout<<rmat[i]<<" ";
62     cout<<endl;
63 }
原文地址:https://www.cnblogs.com/Leohh/p/8439186.html