P2962 [USACO09NOV]Lights G(dfs&高斯消元)
Posted Harris-H
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了P2962 [USACO09NOV]Lights G(dfs&高斯消元)相关的知识,希望对你有一定的参考价值。
P2962 [USACO09NOV]Lights G(dfs&高斯消元)
构造 n × ( n + 1 ) n\\times (n+1) n×(n+1)的方程组。
未知数就是每个点是否操作。
高斯消元后,回代时进行 d f s dfs dfs。
如果是自由元,则分情况搜,否则直接搜。
时间复杂度: O ( 玄 学 ) O(玄学) O(玄学)
// Problem: P2962 [USACO09NOV]Lights G
// Contest: Luogu
// URL: https://www.luogu.com.cn/problem/P2962
// Memory Limit: 125 MB
// Time Limit: 1000 ms
// Date: 2021-09-03 11:07:20
// --------by Herio--------
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int N=1e3+5,M=2e4+5,inf=0x3f3f3f3f,mod=1e9+7;
#define mst(a,b) memset(a,b,sizeof a)
#define PII pair<int,int>
#define x first
#define y second
#define pb emplace_back
#define SZ(a) (int)a.size()
#define rep(i,a,b) for(int i=a;i<=b;++i)
#define per(i,a,b) for(int i=a;i>=b;--i)
#define ios ios::sync_with_stdio(false),cin.tie(0)
void Print(int *a,int n){
for(int i=1;i<n;i++)
printf("%d ",a[i]);
printf("%d\\n",a[n]);
}
int n,m;
int a[N][N],ans[N];
void Gauss(){ //O(n^3)
rep(i,1,n){
int mx=i;
rep(j,i+1,n){
if(a[j][i]) {mx=j;break;}
}
if(mx!=i) swap(a[mx],a[i]);
rep(j,i+1,n){
int x=a[j][i];
if(x) rep(k,i,n+1) a[j][k]^=a[i][k];
}
}
}
int res=inf;
void dfs(int x,int s){
if(s>=res) return;
if(!x) {res=min(res,s);return;}
if(a[x][x]){
ans[x]=a[x][n+1];
rep(i,x+1,n) ans[x]^=a[x][i]&ans[i];
if(ans[x]) dfs(x-1,s+1);
else dfs(x-1,s);
}
else {
ans[x]=0;dfs(x-1,s);
ans[x]=1;dfs(x-1,s+1);
}
}
int main(){
scanf("%d%d",&n,&m);
rep(i,1,m){
int u,v;scanf("%d%d",&u,&v);a[u][v]=a[v][u]=1;
}
rep(i,1,n) a[i][i]=a[i][n+1]=1;
Gauss();dfs(n,0);printf("%d\\n",res);
return 0;
}
还有一个稳定的方法,折半搜索.
分成两段 n 2 \\dfrac{n}{2} 2n进行搜索.
用一个 m a p map map记录前半段对应状态的最小值.
然后再搜索后半段,同时更新答案.
时间复杂度: O ( n 2 n 2 ) O(n2^{\\frac{n}{2}}) O(n22n)
参考代码(题解区)
#include <bits/stdc++.h>
using namespace std;
int n, m, ans = 0x7fffffff;
map<long long, int> f;
long long a[40];
int main(void) {
ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
cin >> n >> m;
a[0] = 1;
for (int i = 1; i < n; ++i) a[i] = a[i - 1] << 1; //预处理每个点都能影响到自己
for (int i = 1; i <= m; ++i) {
int u, v;
cin >> u >> v;
--u,--v; //与二进制位匹配
a[u] |= (1ll << v),a[v] |= (1ll << u); //压位记录每个点操作影响到的点
}
for (int i = 0; i < (1 << (n >> 1)); ++i) { //前半段
long long t = 0; //状态压缩
int cnt = 0;
for (int j = 0; j < (n >> 1); ++j) {
if ((i >> j) & 1) {
t ^= a[j];
++cnt;
}
}
if (!f.count(t)) //前半段记录在 map 里
f[t] = cnt;
else
f[t] = min(f[t], cnt);
}
for (int i = 0; i < (1 << (n - (n >> 1))); ++i) { //后半段
long long t = 0;
int cnt = 0;
for (int j = 0; j < (n - (n >> 1)); ++j) {
if ((i >> j) & 1) {
t ^= a[(n >> 1) + j];
++cnt;
}
}
if (f.count((((long long)1 << n) - 1) ^ t)) //后半段与前半段匹配
ans = min(ans, cnt + f[(((long long)1 << n) - 1) ^ t]);
}
cout << ans;
return 0;
}
以上是关于P2962 [USACO09NOV]Lights G(dfs&高斯消元)的主要内容,如果未能解决你的问题,请参考以下文章
P2962 [USACO09NOV]Lights G(dfs&高斯消元)
P2962 [USACO09NOV]灯Lights 对抗搜索