1. 程式人生 > >[NOI2009]變換序列

[NOI2009]變換序列

分享圖片 LG using 一個點 ems algo size ont n)

Description

技術分享圖片

Input

技術分享圖片

Output

技術分享圖片

Sample Input

5
1 1 2 2 1

Sample Output

1 2 4 0 3

HINT

30%的數據中N≤50;
60%的數據中N≤500;
100%的數據中N≤10000。

二分圖匹配

匈牙利算法的原理是沖突時替換

不過要求字典序最小,一個點會連出2條邊,加邊先加入大的,這樣在匹配時就會先匹配小的

不過這是針對於鏈式前向星

然後如果i和j都匹配了T,且i<j

那麽顯然i配T更好,因為如果不這樣i就要配一個更大的

所以要從後往前枚舉

 1 #include<iostream>
 2
#include<cstdio> 3 #include<cstring> 4 #include<cmath> 5 #include<algorithm> 6 using namespace std; 7 struct Node 8 { 9 int next,to; 10 }edge[50001]; 11 int match[20001],head[20001],num,n,vis[20001],sum,ans[20001]; 12 void add(int u,int v) 13 { 14 num++; 15 edge[num].next=head[u];
16 head[u]=num; 17 edge[num].to=v; 18 } 19 bool dfs(int x) 20 {int i; 21 for (i=head[x];i;i=edge[i].next) 22 { 23 int v=edge[i].to; 24 if (vis[v]==0) 25 { 26 vis[v]=1; 27 if (match[v]==-1||dfs(match[v])) 28 { 29 ans[x]=v;match[v]=x;
30 return 1; 31 } 32 } 33 } 34 return 0; 35 } 36 int main() 37 {int i,x,v1,v2; 38 cin>>n; 39 memset(match,-1,sizeof(match)); 40 for (i=0;i<n;i++) 41 { 42 scanf("%d",&x); 43 v1=i-x;v2=i+x; 44 if (v1<0) v1+=n; 45 if (v2>=n) v2-=n; 46 if (v1<v2) swap(v1,v2); 47 add(i,v1);add(i,v2); 48 } 49 for (i=n-1;i>=0;i--) 50 { 51 memset(vis,0,sizeof(vis)); 52 if (dfs(i)) sum++; 53 else break; 54 } 55 if (sum<n) 56 { 57 cout<<"No Answer\n"; 58 return 0; 59 } 60 for (i=0;i<n-1;i++) 61 printf("%d ",ans[i]); 62 cout<<ans[n-1]; 63 }

[NOI2009]變換序列