P2962 [USACO09NOV]灯Lights
P2962 [USACO09NOV]灯Lights
guass消元异或方程组
#include<bits/stdc++.h> using namespace std; #define maxn 100 #define sc(x) scanf("%lld",&x); #define int long long int A[maxn][maxn]; int x[maxn]; int ans=1000; int n,m; void guass() { for(int i=1; i<=n; i++) { int t=i; if(!A[t][t]) { for(int j=i+1; j<=n; j++) { if(A[j][i]) { t=j; break; } } swap(A[i],A[t]); } for(int k=i+1; k<=n; k++) { if(A[k][i]) { for(int j=1; j<=n+1; j++) { A[k][j]^=A[i][j];///消元 } } } } } void dfs(int i,int t) { if(t>ans)return; if(i==0){ ans=min(t,ans); return; } if(A[i][i]){ x[i]=A[i][n+1]; for(int j=i+1;j<=n;j++) if(A[i][j]){x[i]^=x[j];} if(x[i])dfs(i-1,t+1); else dfs(i-1,t); }else{ x[i]=0; dfs(i-1,t); x[i]=1; dfs(i-1,t+1); } } signed main() { sc(n);sc(m); int x,y; while(m--){ sc(x);sc(y); A[x][y]=A[y][x]=1; } for(int i=1;i<=n;i++)A[i][i]=A[i][n+1]=1; guass(); dfs(n,0); cout<<ans<<'\n'; }
折半枚举
#include<bits/stdc++.h> #define LL long long #define RI register int using namespace std; const int INF = 0x7ffffff ; const int N = 40 ; inline int read() { int k = 0, f = 1 ; char c = getchar() ; for( ; !isdigit(c) ; c = getchar()) if(c == '-') f = -1 ; for( ; isdigit(c) ; c = getchar()) k = k*10 + c-'0' ; return k*f ; } int n, m, lv, ans = INF ; LL hh[N] ; LL tt ; LL p1[N], bin[N] ; bool flag ; map<LL,int>p ; // 开不下2^35的数组,其实最多只有2^18个状态,所以用map是可以的 void dfs(int now,LL res,int used) { if(now > lv) { if(res == tt) { ans = min(ans,used) ; } else { if(!flag) { int t = p[res] ; if(!t || used < t) p[res] = used ; } else { if(p[tt^res]) ans = min(ans,p[tt^res]+used) ; } } return ; } dfs(now+1,res^p1[now],used+1) ; dfs(now+1,res,used) ; // 选与不选 } int main() { n = read(), m = read() ; bin[0] = 1 ; for(int i=1; i<=n; i++) bin[i] = bin[i-1]<<1 ; tt = bin[n] - 1 ; memset(hh,0,sizeof(hh)) ; LL x, y ; for(int i=1; i<=m; i++) { x = read(), y = read() ; hh[x] ^= bin[y-1], hh[y] ^= bin[x-1] ; } for(int i=1; i<=n; i++) hh[i] ^= bin[i-1] ; lv = n>>1 ; for(int i=1; i<=lv; i++) p1[i] = hh[i] ; dfs(1,0,0) ; // 搜索前一半 for(int i=1; i<=n-lv; i++) p1[i] = hh[i+lv] ; lv = (n+1)>>1 ; flag = 1 ; // flag标记在搜索前半段还是后半段 dfs(1,0,0) ; // 搜索后一半 printf("%d",ans) ; return 0 ; }