1. 程式人生 > >BZOJ 1562 [NOI2009]變換序列:二分圖匹配

BZOJ 1562 [NOI2009]變換序列:二分圖匹配

ostream i++ log 滿足 code pos 要求 兩個 spa

題目鏈接: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 }

BZOJ 1562 [NOI2009]變換序列:二分圖匹配