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 对抗搜索

灯Lights[USACO09NOV]

luogu2962 [USACO09NOV]灯Lights

BZOJ 1770: [Usaco2009 Nov]lights 燈

BZOJ 1770: [Usaco2009 Nov]lights 燈