高斯消元小结

1.bzoj 1013 球形空间产生器sphere

最裸的高斯消元,直接套版

设球心坐标为(x1,x2...xn)

那么对于任意两点都可以建立一个方程: (x1-a1)2+(x2-a2)2...+(xn-an)2=(x1-b1)2+(x2-b2)2+...+(xn-bn)2

移项后可得: 2(a1-b1)x1+2(a2-b2)x2+ ... +2(an-bn)xn=a12-b12+...+an2-bn2

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <iostream>
 4 #include <cmath>
 5 using namespace std;
 6 const double eps=1e-10;
 7 double x,b[30],a[30][30];
 8 int n;
 9 
10 void gauss() {
11     for (int i=1;i<=n;i++) {
12         int p=i;
13         while (p<=n&&fabs(a[p][i])<eps) p++;
14         if (fabs(a[p][i])>eps) {
15             if (i^p) for (int j=i+1;j<=n+1;j++) swap(a[p][j],a[i][j]);
16             double t=a[i][i];
17             for (int j=i+1;j<=n+1;j++) a[i][j]/=t;
18             for (int j=1;j<=n+1;j++) if (i^j) {
19                 t=a[j][i];
20                 for (int k=1;k<=n+1;k++)
21                     a[j][k]-=t*a[i][k];
22             }
23         }
24     }
25 }
26 
27 int main()
28 {
29     scanf("%d",&n);
30     for (int i=1;i<=n;i++) scanf("%lf",&b[i]);
31     for (int i=1;i<=n;i++) {
32         for (int j=1;j<=n;j++) {
33             scanf("%lf",&x);
34             a[i][j]=2*(x-b[j]);
35             a[i][n+1]+=x*x-b[j]*b[j];
36             b[j]=x;
37         }
38     }
39     gauss();
40     for (int i=1;i<=n;i++) {
41         printf("%.3lf",a[i][n+1]);
42         if (i<n) printf(" ");
43         else puts("");
44     }
45     return 0;
46 }
View Code

2.poj 1222 EXTENDED LIGHTS OUT

解法一、暴力枚举 枚举第一行每个关不关。一行处理完后用这一行的状态去推下一行每个关不关最后check。

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <iostream>
 4 using namespace std;
 5 
 6 int a[10][10],b[10][10],c[10][10],T,cas;
 7 
 8 bool ok() {
 9     for (int i=1;i<=6;i++)
10         if (a[5][i]) return false;
11     return true;
12 }
13 void press(int i,int j) {
14     a[i][j]^=1;
15     if (i>1) a[i-1][j]^=1;
16     if (i<5) a[i+1][j]^=1;
17     if (j>1) a[i][j-1]^=1;
18     if (j<6) a[i][j+1]^=1;
19 }
20 
21 int main()
22 {
23     scanf("%d",&T);
24     while (++cas<=T) {
25         memset(b,0,sizeof(b));
26         for (int i=1;i<=5;i++)
27             for (int j=1;j<=6;j++)
28                 scanf("%d",&c[i][j]);
29         printf("PUZZLE #%d\n",cas);
30         for (int i=0;i<(1<<6);i++) {
31             for (int j=1;j<=5;j++)
32                 for (int k=1;k<=6;k++)
33                     a[j][k]=c[j][k];
34             memset(b,0,sizeof(b));
35             int pos=i;
36             for (int j=1;j<=5;j++) {
37                 int w=0;
38                 for (int k=1;k<=6;k++)
39                     if (1<<(k-1)&pos) press(j,k),b[j][k]^=1;
40                 for (int k=1;k<=6;k++) 
41                     if (a[j][k]) w|=1<<(k-1);
42                 pos=w;
43             }
44             if (ok()) {
45                 for (int j=1;j<=5;j++,puts(""))
46                     for (int k=1;k<=6;k++)
47                         printf("%d ",b[j][k]);
48                 break;
49             }
50         }
51     }
52     
53     return 0;
54 }
View Code

解法二、高斯消元 可以发现对于每个点a[i][j](目前状态),b[i][j]为答案(暂不考虑边界) 有b[i][j]^b[i-1][j]^b[i][j-1]^b[i+1][j]^b[i][j+1]=a[i][j] 就可以建立30个异或方程。 然后解出方程即得答案

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <iostream>
 4 #include <algorithm>
 5 using namespace std;
 6 
 7 int a[35][35],T,cas;
 8 
 9 void gauss() {
10     for (int i=1;i<=30;i++) {
11         int p=i;
12         while (p<=30&&a[p][i]==0) p++;
13         if (p^i) 
14             for (int j=1;j<=31;j++) swap(a[i][j],a[p][j]);
15         for (int k=1;k<=30;k++) {
16             if (i!=k&&a[k][i]) {
17                 for (int j=1;j<=31;j++) a[k][j]^=a[i][j];
18             }
19         }
20     }
21 }
22 int bs(int x){return x>0?x:-x;}
23 
24 int main()
25 {
26     scanf("%d",&T);
27     while (++cas<=T) {
28         for (int i=1;i<=30;i++)    scanf("%d",&a[i][31]);
29         for (int i=1;i<=30;i++) {
30             int x=(i-1)/6,y=(i-1)%6;
31             for (int j=1;j<=30;j++) {
32                 int xx=(j-1)/6,yy=(j-1)%6;
33                 a[i][j]=(bs(x-xx)+bs(y-yy))<=1;
34             }
35         }
36         gauss();
37         printf("PUZZLE #%d\n",cas);
38         for (int i=1;i<=30;i++) {
39             printf("%d ",a[i][31]);
40             if (!(i%6)) puts("");
41         }
42     }
43     
44     return 0;
45 }
View Code

3.poj 1830 开关问题

此题跟上题差不多,不过要求一个自由变元的数量r,则ans=1<<r。当然还需判断无解。

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <iostream>
 4 using namespace std;
 5 
 6 int T,n,a[50][50],x,y,s[50],e[50];
 7 
 8 int gauss() {
 9     int cnt=1;
10     for (int i=1;i<=n;i++) {
11         int p=i;
12         while (p<=n&&!a[p][i]) p++;
13         if (a[p][i]) {
14             for (int j=1;j<=n+1;j++) swap(a[cnt][j],a[p][j]);
15             for (int j=1;j<=n;j++) {
16                 if (cnt!=j&&a[j][i]) {
17                     for (int k=1;k<=n+1;k++) a[j][k]^=a[cnt][k];
18                 }
19             }
20             cnt++;
21         }
22     }
23     for (int i=cnt;i<=n;i++) 
24         if (a[i][n+1]) return -1;
25     return n-cnt+1;
26 }
27 
28 int main()
29 {
30     scanf("%d",&T);
31     while (T--) {
32         scanf("%d",&n);
33         memset(a,0,sizeof(a));
34         for (int i=1;i<=n;i++) scanf("%d",&s[i]);
35         for (int i=1;i<=n;i++) {
36             scanf("%d",&e[i]);
37             if (s[i]^e[i]) a[i][n+1]=1;
38             a[i][i]=1;
39         }
40         while (scanf("%d%d",&x,&y)&&x+y) a[y][x]=1;
41         int ans=gauss();
42         if (ans==-1) puts("Oh,it's impossible~!!");
43         else printf("%lld\n",1LL<<ans);
44     }
45     
46     return 0;
47 }
View Code

4.bzoj 1923 外星千足虫

又是同样的异或方程组。 数据范围貌似有点大。要用个bitset。

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <iostream>
 4 #include <bitset>
 5 using namespace std;
 6 int n,m;
 7 bool read() {
 8     char c=getchar();
 9     while (c>'1'||c<'0') c=getchar();
10     return c=='1';
11 }
12 bitset <1005> a[2005];
13 
14 int gauss() {
15     int ret=0;
16     for (int i=1;i<=n;i++) {
17         int p=i;
18         while (p<=m&&!a[p][i]) p++;
19         if (p>m) return -1;
20         ret=max(ret,p);
21         if (i^p) swap(a[p],a[i]);
22         for (int j=1;j<=m;j++) 
23             if (i^j&&a[j][i]) a[j]^=a[i];
24     }
25     return ret;
26 }
27 
28 int main()
29 {
30     scanf("%d%d",&n,&m);
31     for (int i=1;i<=m;i++)
32         for (int j=1;j<=n+1;j++)
33             a[i][j]=read();
34     int ans=gauss();
35     if (ans==-1) puts("Cannot Determine");
36     else {
37         printf("%d\n",ans);
38         for (int i=1;i<=n;i++) {
39             if (a[i][n+1]) puts("?y7M#");
40             else puts("Earth");
41         }
42     }    
43     return 0;
44 }
View Code

5.bzoj 2115 [Wc2011] Xor

链^环=链。找到一条到n链以及所有环。

那么,就是相当于给你一些数,然后Xor出最大的结果就完了。是不是线性基裸题了?

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <iostream>
 4 using namespace std;
 5 typedef long long ll;
 6 struct edge {
 7     int v,next;ll w;
 8 }e[200005];
 9 ll read() {
10     char c=getchar();ll x=0;
11     while (c<'0'||c>'9') c=getchar();
12     while (c>='0'&&c<='9') x=x*10+c-'0',c=getchar();
13     return x;
14 }
15 ll ans,p[70],a[200005],f[100005];
16 int n,m,k,cnt,head[200005],vis[100005];
17 
18 void adde(int u,int v,ll w) {
19     e[k].v=v;e[k].w=w;e[k].next=head[u];head[u]=k++;
20 }
21 void dfs(int u) {
22     vis[u]=1;
23     for (int i=head[u];~i;i=e[i].next) {
24         int v=e[i].v;
25         if (!vis[v]) {
26             f[v]=f[u]^e[i].w;dfs(v);
27         }else a[++cnt]=f[u]^e[i].w^f[v];
28     }
29 }
30 
31 int main()
32 {
33     memset(head,-1,sizeof(head));
34     n=read();m=read();
35     for (int i=1;i<=m;i++) {
36         int x,y;ll z;
37         x=read();y=read();z=read();
38         adde(x,y,z);adde(y,x,z);
39     }
40     dfs(1);
41     for (int i=1;i<=cnt;i++) {
42         for (int j=63;j>=0;j--) {
43             if ((a[i]>>j)&1) {
44                 if (!p[j]) {p[j]=a[i];break;}
45                 a[i]^=p[j];
46             }
47         }
48     }
49     ans=f[n];
50     for (int i=63;i>=0;i--) ans=max(ans,ans^p[i]);
51     printf("%lld\n",ans);    
52     return 0;
53 }
View Code

6.bzoj 2460 元素

按magic排个序贪心就完了

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <iostream>
 4 #include <algorithm>
 5 using namespace std;
 6 typedef long long ll;
 7 int n,ans;
 8 ll p[70];
 9 struct E {
10     ll num;int w;
11     bool operator < (const E&b) const {
12         return w>b.w;
13     }
14 }a[1005];
15 
16 int main()
17 {
18     scanf("%d",&n);
19     for (int i=1;i<=n;i++) scanf("%lld%d",&a[i].num,&a[i].w);
20     sort(a+1,a+n+1);
21     for (int i=1;i<=n;i++) {
22         for (int j=63;j>=0;j--) {
23             if (a[i].num&(1ll<<j)) {
24                 if (!p[j]) {p[j]=a[i].num;break;}
25                 a[i].num^=p[j];
26             }
27         }
28         if (a[i].num) ans+=a[i].w;
29     }
30     printf("%d\n",ans);
31     return 0;
32 }
View Code

7.bzoj 2337 XOR和路径

看到位运算,就按位处理,考虑每一位对答案的贡献w[i],则ans=∑w[i]*(1<<i);

对于每一位:

  f[x]表示从x到n二进制下这一位异或和为1的概率

  i(w==0f(u)=∑f(v)/deg[u] 
  elsf(u)=(1−f(v))/deg[u]

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <iostream>
 4 #include <cmath>
 5 using namespace std;
 6 struct edge {
 7     int v,w,next;
 8 }e[20005];
 9 const double eps=1e-10;
10 int k,n,m,head[205],d[205];
11 double ans,a[105][105];
12 void adde(int u,int v,int w) {
13     e[k].v=v;e[k].w=w;e[k].next=head[u];head[u]=k++;
14 }
15 
16 void gauss() {
17     for (int i=1;i<=n;i++) {
18         int p=i;
19         while (p<=n&&fabs(a[p][i])<eps) p++;
20         if (fabs(a[p][i])>eps) {
21             if (i^p) for (int j=1;j<=n+1;j++) swap(a[i][j],a[p][j]);
22             double t=a[i][i];
23             for (int j=1;j<=n+1;j++) a[i][j]/=t;
24             for (int j=1;j<=n;j++) if (i^j) {
25                 t=a[j][i];
26                 for (int k=i;k<=n+1;k++) {
27                     a[j][k]-=t*a[i][k];
28                 }
29             }
30         }
31     }
32 }
33 
34 int main()
35 {
36     memset(head,-1,sizeof(head));
37     scanf("%d%d",&n,&m);
38     for (int i=1,u,v,w;i<=m;i++) {
39         scanf("%d%d%d",&u,&v,&w);
40         adde(u,v,w);d[v]++;
41         if (u^v) adde(v,u,w),d[u]++;
42     }
43     for (int i=0;i<=30;i++) {
44         memset(a,0,sizeof(a));
45         for (int j=1;j<n;j++) {
46             a[j][j]=1.;
47             for (int k=head[j];~k;k=e[k].next) {
48                 int v=e[k].v;
49                 if (e[k].w>>i&1) a[j][v]+=1./d[j],a[j][n+1]+=1./d[j];
50                 else a[j][v]-=1./d[j];
51             }
52         }
53         a[n][n]=1.;
54         gauss();
55         ans+=(1<<i)*a[1][n+1];
56     }
57     printf("%.3lf\n",ans);    
58     return 0;
59 }
View Code

8.hdu 4870 Rating

题目大意:小女孩注册了两个比赛的帐号,初始分值都为0,每做一次比赛如果排名在前两百名,rating涨50,否则降100(最低为0),告诉你她每次比赛在前两百名的概率p,如果她每次做题都用两个账号中分数低的那个去做,问她最终有一个账号达到1000分需要做的比赛的次数的期望值。

将0,50,100...1000看做0,1,2...20.

定义f[i][j](i≥j)表示从(i,j)状态到(1000,?)的期望值,则有: f[i][j]=success*p+failure*(1-p)+1;

移项得: f[i][j]-success*p-failure*(1-p)=1; 即可求出ans;

状态有点麻烦,可分i>j和i=j讨论。

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <iostream>
 4 #include <algorithm>
 5 #include <cmath>
 6 using namespace std;
 7 const double eps=1e-10;
 8 
 9 double a[220][220],p;
10 int n,b[25][25];
11 
12 void gauss() {
13     for (int i=1;i<=n;i++) {
14         int p=i;
15         while (p<=n&&fabs(a[p][i])<eps) p++;
16         if (fabs(a[p][i])>eps) {
17             if (i^p) for (int j=1;j<=n+1;j++) swap(a[i][j],a[p][j]);
18             double t=a[i][i];
19             for (int j=1;j<=n+1;j++) a[i][j]/=t;
20             for (int j=1;j<=n;j++) if (i^j) {
21                 t=a[j][i];
22                 for (int k=i;k<=n+1;k++) 
23                     a[j][k]-=t*a[i][k];
24             }
25         }
26     }
27 }
28 
29 void build() {
30     for (int i=0,t;i<20;i++) {
31         for (int j=0;j<i;j++) {
32             t=b[i][j];
33             a[t][t]=1;a[t][n+1]=1;
34             a[t][b[i][j+1]]-=p;
35             a[t][b[i][max(j-2,0)]]-=1-p;
36         }
37         t=b[i][i];
38         a[t][t]=1;a[t][n+1]=1;
39         a[t][b[i+1][i]]-=p;
40         a[t][b[i][max(i-2,0)]]-=1-p;
41     }
42 }
43 
44 int main()
45 {
46     for (int i=0;i<20;i++)
47         for (int j=0;j<=i;j++)
48             b[i][j]=++n;
49     while (scanf("%lf",&p)^EOF) {
50         memset(a,0,sizeof(a));
51         build();gauss();
52         printf("%.6lf\n",a[1][n+1]);
53     }
54     return 0;
55 }
View Code

 

posted @ 2016-12-19 16:43  yanglang  阅读(134)  评论(0编辑  收藏  举报