BZOJ 1562 [NOI2009] 變換序列
阿新 • • 發佈:2019-02-03
b2b ace size char com 當前 set log 就是
[NOI2009] 變換序列
[題解]
就是有一個序列,每個位置可以填兩個數,不可重復,問最小字典序。
顯然,可以建一個二分圖,判合法就是找完美匹配。
那怎麽弄最小字典序呢?有好多種解法,我這裏給出了兩種。
解法一:
先求出它的一個完美匹配,把每個點掃一遍,如果它連的點是它能連的最小的了,就不管他,否則強制將當前節點與其能連的最小點對應,這時從這個點找增廣路,如果有,就算修正成功,否則修正失敗。
這個方法的好處是通用,時間復雜度O(n*n)
解法二:
從最後一個點開始求增廣路,求增廣路時優先考慮序號較小點。
證明:daolao博客。
代碼:
這裏給出解法二的代碼。
#include<iostream> #includeView Code<algorithm> #include<cstring> #include<cstdio> #include<cstdlib> #include<string> #include<cmath> #include<queue> #define SIZE 100005 #define rint register int using namespace std; inline int read() { int x=0,f=1;char ch=getchar(); for(;!isdigit(ch);ch=getchar()) if(ch==‘-‘) f=-1; for(;isdigit(ch);ch=getchar()) x=x*10+ch-‘0‘; return x*f; } inline void write(int x) { if(x<0) putchar(‘-‘),x=-x; if(x>9) write(x/10); putchar(x%10+‘0‘); return ; } int n,match[SIZE],ans[SIZE],cnt; int d[SIZE],vis[SIZE],f[3][SIZE]; int dfs(int x) { for(rint i=1;i<=2;++i) { int y=f[i][x];if(vis[y]) continue; vis[y]=1; if(match[y]==-1 || dfs(match[y])) { match[y]=x;ans[x]=y; return 1; } } return 0; } inline void clear() { memset(match,-1,sizeof(match)); memset(ans,0,sizeof(ans)); } int main() { n=read();clear(); for(rint i=0;i<n;++i) d[i]=read(); for(rint i=0;i<n;++i) { int a=(i-d[i]+n)%n,b=(i+d[i])%n; if(a>b) swap(a,b); f[1][i]=a,f[2][i]=b; } for(rint i=n-1;i>=0;--i) { memset(vis,0,sizeof(vis)); if(dfs(i)) ++cnt; } if(cnt<n) return puts("No Answer"),0; for(rint i=0;i<n;++i) { write(ans[i]); if(i!=n) cout<<" "; } return 0; }
BZOJ 1562 [NOI2009] 變換序列