[USACO09NOV]灯Lights

【题意】

  同poj1830,但是求的是最小开关次数,保证有解

【题解】

  高斯消元,再对自由元暴力枚举。暴力的时候要记得剪枝。

  高斯消元优化很悬。。。其实有n个自由元的时候就相当于纯暴力了。似乎还有种可靠的折半写法。。。。

  反正就当练习高斯消元了。

【代码】

 1 #include <iostream>
 2 #include <cstring>
 3 #include <cstdio>
 4 using namespace std;
 5 struct node
 6 {
 7     int c,vec[40];
 8 }a[40];
 9 int n,m,ans,X[40],dt[40],kw[40],po,cnt,x,y;
10 void dfs(int t,int s)
11 {
12     if (s>=ans) return;
13     if (t>cnt)
14     {        
15         for (int i=po;i;--i)
16         {
17             int y=a[i].c;
18             for (int j=kw[i]+1;j<=n;++j)
19                 if (a[i].vec[j])    y^=X[j];
20             X[kw[i]]=y;
21             s+=y;
22         }                
23         if (s<ans)    ans=s;
24         return;
25     }
26     X[dt[t]]=0;
27     dfs(t+1,s);
28     X[dt[t]]=1;
29     dfs(t+1,s+1);
30 }
31 void gauss()
32 {
33     for (int i=1,o=1;o<=n;)
34     {
35         for (int j=i;j<=n;++j)
36             if (a[j].vec[o])
37             {
38                 swap(a[i],a[j]);
39                 break;
40             }
41         if (!a[i].vec[o])
42         {
43             dt[++cnt]=o;
44             ++o;
45             continue;
46         }
47         for (int j=i+1;j<=n;++j)
48             if (a[j].vec[o])
49             {
50                 if (a[i].c)    a[j].c^=1;
51                 for (int k=o;k<=n;++k)
52                     if (a[i].vec[k])
53                         a[j].vec[k]^=1;                    
54             }
55         kw[i]=o;
56         po=i;++i;++o;
57     }    
58 }
59 int main()
60 {
61     scanf("%d%d",&n,&m);
62     for (int i=1;i<=n;++i)
63         a[i].vec[i]=1,
64         a[i].c=1;
65     for (int i=1;i<=m;++i)
66     {
67         scanf("%d%d",&x,&y);
68         a[x].vec[y]=1;
69         a[y].vec[x]=1;
70     }
71     gauss();
72     ans=n;    
73     dfs(1,0);
74     cout<<ans<<endl;
75     return 0;
76 }
View Code
原文地址:https://www.cnblogs.com/Bleacher/p/7587496.html