zoukankan      html  css  js  c++  java
  • AcWing 208. 开关问题 (高斯消元+状压)打卡

    有N个相同的开关,每个开关都与某些开关有着联系,每当你打开或者关闭某个开关的时候,其他的与此开关相关联的开关也会相应地发生变化,即这些相联系的开关的状态如果原来为开就变为关,如果为关就变为开。

    你的目标是经过若干次开关操作后使得最后N个开关达到一个特定的状态。

    对于任意一个开关,最多只能进行一次开关操作。

    你的任务是,计算有多少种可以达到指定状态的方法。(不计开关操作的顺序)

    输入格式

    输入第一行有一个数K,表示以下有K组测试数据。

    每组测试数据的格式如下:

    第一行 一个数N(0 < N < 29)。

    第二行 N个0或者1的数,表示开始时N个开关状态。

    第三行 N个0或者1的数,表示操作结束后N个开关的状态。

    接下来 每行两个数I J,表示如果操作第 I 个开关,第J个开关的状态也会变化。

    每组数据以 0 0 结束。

    输出格式

    如果有可行方法,输出总数,否则输出“Oh,it’s impossible~!!” 。

    输入样例:

    2
    3
    0 0 0
    1 1 1
    1 2
    1 3
    2 1
    2 3
    3 1
    3 2
    0 0
    3
    0 0 0
    1 0 1
    1 2
    2 1
    0 0
    

    输出样例:

    4
    Oh,it's impossible~!!



    题意:有n盏灯,现在给了这n盏灯的初始状态,还有要最终状态,最终状态要通过你进行了x次操作后得到
    每个灯最多进行一次操作,其中灯与灯之间有关系,如果开这个灯另一个灯也会改变状态,现在求有多少种操作可以满足达到最终状态

    思路:我们可以化成n个式子
    aij 代表按j开关会影响i开关,xi代表按i开关 ,begin 代表初始状态,end代表最终状态
    a11*x1^a12*x2^a13*x3....=begin^end // 这是计算1开关进行了多少次操作,两边执行次数要相等
    ......
    ......
    ......
    ......

    这里我们可以用状态压缩代表一行的状态,0位代表常数是多少,1-n位代表系数式为多少,XOR其实也相当于+法,后面矩阵消元的时候也用XOR
    本题求的是方案数,我们初值为1,但是一旦有自由元,原先有自由元就代表当前有无数个解,这里只有0,1两种情况
    所以答案为 1<<cnt

    #include<bits/stdc++.h>
    #define maxn 100005
    #define mod 1000000007
    using namespace std;
    typedef long long ll;
    ll a[200];
    int main(){
        ll t;
        cin>>t;
        while(t--){
            ll n;
            cin>>n;
            for(int i=1;i<=n;i++) cin>>a[i];
            for(int i=1;i<=n;i++){
                ll z;
                cin>>z;
                a[i]^=z;
                a[i]|=(1<<i);
            }
            ll x,y;
            while(cin>>x>>y){
                if(x==0&&y==0) break;
                a[y]|=(1<<x);
            }
            ll ans=1;
            for(int i=1;i<=n;i++){
                for(int j=i+1;j<=n;j++){
                    if(a[i]<a[j]) swap(a[i],a[j]);//这里求出当前最大元系数
                }
                if(a[i]==0){//等于0,代表系数+常数都等于0,代表当前行全为0,那么直接推出,后面几位全为自由元,因为上面求的是最大值
                //    cout<<"i:"<<i<<endl;
                    ans=1<<(n-i+1); 
                    break; 
                }
                if(a[i]==1){//为1代表  常数=1 ,因为是状压形态存储,所以肯定是第0位为1,这里就造成无解情况  0=1
                    ans=0;
                    break;
                }
                for(int k=n;k>=1;k--){  //这里我们从高到低位枚举到最高的位的元让然后遍历 ,为什么我们不直接用第i位呢,因为我们需要从高到低枚举,前面找的最大值
                    if(a[i]>>k&1){
                        for(int j=1;j<=n;j++){
                            if(i!=j&&(a[j]>>k&1)){
                                a[j]^=a[i];
                            }
                        }
                        break;
                    }
                }
            }
            if(ans==0){
                cout<<"Oh,it's impossible~!!"<<endl;
            }
            else{
                cout<<ans<<endl;
            } 
        } 
    }
    
    
    
     
  • 相关阅读:
    c++中 . 和 -> 的区别是什么?
    codeblocks中一个简单的程序的创建。
    将牛客中的代码在codeblocks中进行实现
    (全代码)输入一颗二叉树的跟节点和一个整数,打印出二叉树中结点值的和为输入整数的所有路径。路径定义为从树的根结点开始往下一直到叶结点所经过的结点形成一条路径。(注意: 在返回值的list中,数组长度大的数组靠前)
    解决You are using pip version 10.0.1, however version 18.1 is available. You should consider upgrading via the 'python -m pip install --upgrade pip' command.
    mysql 表复制(表备份)
    Scrapy 抓取股票行情
    去哪儿网数据爬取
    用API爬取天气预报数据
    爬虫防封IP
  • 原文地址:https://www.cnblogs.com/Lis-/p/11099403.html
Copyright © 2011-2022 走看看