zoukankan      html  css  js  c++  java
  • poj 1681 Painter's Problem

    Painter's Problem

    题意:给一个n*n(1 <= n <= 15)具有初始颜色(颜色只有yellow&white两种,即01矩阵)的square染色,每次对一个方格染成黄色时,同时会把周围的方格也染成黄色。(这和1222的开关一样的关联关系)问最后可以将square全部染成黄色的最小染色方格数?

    思路:

    1.直接预处理出增广矩阵,和1222不同的是里面有最优解的条件,贪心的思想是把自由变元看成是没染色的,但是其他非自由变元(除去自由维度之外的变量)是可以通过自由变元的取值来确定的(在poj 1753中WA了很久,有是一个坑), 但是这道题确实可以不用枚举过。。

    2.本题的var = 15*15,变量的个数很大,直接枚举自由变元会不会导致枚举TLE?或者二进制枚举爆数位?这就转化为了方程自由变元的最大个数?如果只考虑高斯消元的全部变量,虽然可以从之间的关联来看会极大的减小自由度,却依旧难证明。但是如果从枚举第一行,就可以递推出全部结果就知道其实是一个一维的自由度,不超过15~~

    code1:直接将自由元看成0...(也能A,不够严谨)0ms..

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<string.h>
    #include<algorithm>
    #include<map>
    #include<queue>
    #include<vector>
    #include<cmath>
    #include<stdlib.h>
    #include<time.h>
    using namespace std;
    #define rep0(i,l,r) for(int i = (l);i < (r);i++)
    #define rep1(i,l,r) for(int i = (l);i <= (r);i++)
    #define rep_0(i,r,l) for(int i = (r);i > (l);i--)
    #define rep_1(i,r,l) for(int i = (r);i >= (l);i--)
    #define MS0(a) memset(a,0,sizeof(a))
    #define MS1(a) memset(a,-1,sizeof(a))
    
    int dir[2][4] = {{0,1,0,-1},{1,0,-1,0}};
    int a[230][230];
    int equ,var;
    int x[230],free_var[230];
    void debug()
    {
        puts("********");
        int i,j;
        rep0(i,0,equ){
            rep1(j,0,var)
                cout<<a[i][j]<<" ";
            cout<<endl;
        }puts("********");
    }
    int Guass()
    {
        int i,j,k,row,col,cnt = 0;
        for(row = 0,col = 0;row < equ && col < var;row++,col++){
            int mx = row;
            rep0(j,row+1,equ)
                if(abs(a[j][col]) > abs(a[mx][col]))  mx = j;
            if(a[mx][col] == 0){
                row--;  // 行不变;不能通过这里记录自由变元的个数,只能记录没用的col
                free_var[col] = ++cnt;//记录自由变元的标号;
                continue;
            }
            if(mx != row)
                rep1(k,col,var)
                    swap(a[row][k],a[mx][k]);
            rep0(j,row+1,equ){
                if(a[j][col]){
                    rep1(k,col,var)
                        a[j][k] ^= a[row][k];
                }
            }
        }
        //debug();
        int use_equ = row;  //有用的方程数即能确定的变元的个数
        rep0(i,use_equ,equ)
            if(a[i][var] != 0) return -1;    //无解
        //if(use_equ < var) return var - use_equ;//row表示有用的方程数方程,但是要在判断出有解的前提下才能说有多组解;
        rep_1(i,use_equ-1,0){
            x[i] = a[i][var];
            rep0(j,i+1,use_equ)
                x[i] ^= (a[i][j] && x[j]);  //第j个灯会影响到第i盏灯,同时第j盏灯也会亮
        }
    }
    void init(int n)
    {
        int i,j,k;
        rep0(i,0,n)
            rep0(j,0,n){
                int id = i*n+j;
                a[id][id] = 1;
                rep0(k,0,4){
                    int nx = i + dir[0][k] ,ny = j + dir[1][k];
                    if(nx < 0 || nx >= n || ny < 0 || ny >= n) continue;
                    a[nx*n+ny][id] = 1;
                }
            }
    }
    int main()
    {
        int T,n,i;
        cin>>T;
        while(T--){
            MS0(x);MS0(a);MS0(free_var);
            scanf("%d",&n);
            equ = var = n*n ;
            rep0(i,0,var){
                char c = getchar();
                if(c == 'w') a[i][var] = 1;
                else if(c == 'y') a[i][var] = 0;
                else i--;
            }
            init(n);
            int ret = Guass();
            if(ret == -1) puts("inf");
            else{
                int ans = 0;
                rep0(i,0,var)if(free_var[i] == 0)
                    ans += x[i];
                printf("%d
    ",ans);
            }
        }
        return 0;
    }
    View Code

     code2:枚举自由变元:(16ms)

    注意:含有自由变元的式子也是等式。。就是指开始枚举出了自由变量的个数,在后面会不会重复计算。

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<string.h>
    #include<algorithm>
    #include<map>
    #include<queue>
    #include<vector>
    #include<cmath>
    #include<stdlib.h>
    #include<time.h>
    using namespace std;
    #define rep0(i,l,r) for(int i = (l);i < (r);i++)
    #define rep1(i,l,r) for(int i = (l);i <= (r);i++)
    #define rep_0(i,r,l) for(int i = (r);i > (l);i--)
    #define rep_1(i,r,l) for(int i = (r);i >= (l);i--)
    #define MS0(a) memset(a,0,sizeof(a))
    #define MS1(a) memset(a,-1,sizeof(a))
    #define inf 0x3f3f3f3f
    int dir[2][4] = {{0,1,0,-1},{1,0,-1,0}};
    int a[230][230];
    int equ,var;
    int x[230],free_var[230];
    void debug()
    {
        puts("********");
        int i,j;
        rep0(i,0,equ){
            rep1(j,0,var)
                cout<<a[i][j]<<" ";
            cout<<endl;
        }puts("********");
    }
    int Guass()
    {
        int i,j,k,row,col,cnt = 0;
        for(row = 0,col = 0;row < equ && col < var;row++,col++){
            int mx = row;
            rep0(j,row+1,equ)
                if(abs(a[j][col]) > abs(a[mx][col]))  mx = j;
            if(a[mx][col] == 0){
                row--;  // 行不变;不能通过这里记录自由变元的个数,只能记录没用的col
                free_var[cnt++] = col;//记录自由变元的标号;
                continue;
            }
            if(mx != row)
                rep1(k,col,var)
                    swap(a[row][k],a[mx][k]);
            rep0(j,row+1,equ){
                if(a[j][col]){
                    rep1(k,col,var)
                        a[j][k] ^= a[row][k];
                }
            }
        }
        //debug();
        //row即为有用的方程数即能确定的变元的个数
        rep0(i,row,equ)
            if(a[i][var] != 0) return -1;    //无解
        //枚举自由变元,row表示有用的方程数方程,但是要在判断出有解的前提下才能说有多组解;
        //if(row < var) return var - row;   //当不需要枚举时,直接返回自由变元的个数
        int ans = inf,tot = 1 <<(var - row);
        rep0(i,0,tot){
            int cnt = 0,tmp = i;
            rep0(j,0,var - row){
                x[free_var[j]] = (tmp&1);
                if(x[free_var[j]]) cnt++;//**
                tmp >>= 1;
            }
            rep_1(i,row-1,0){   //自由变元不会相互影响,所以可以不分
                x[i] = a[i][var];//现在赋为a[i][var],若为自由变元之后还是会等于0,不会重复计算;
                rep0(j,i+1,equ){
                    x[i] ^= (a[i][j] && x[j]);  //第j个灯会影响到第i盏灯,同时第j盏灯也会亮
                }
                if(x[i]) cnt++;
            }
            ans = min(ans,cnt);
        }
        return ans;
    }
    void init(int n)
    {
        int i,j,k;
        rep0(i,0,n)
            rep0(j,0,n){
                int id = i*n+j;
                a[id][id] = 1;
                rep0(k,0,4){
                    int nx = i + dir[0][k] ,ny = j + dir[1][k];
                    if(nx < 0 || nx >= n || ny < 0 || ny >= n) continue;
                    a[nx*n+ny][id] = 1;
                }
            }
    }
    int main()
    {
        int T,n,i;
        cin>>T;
        while(T--){
            MS0(x);MS0(a);MS0(free_var);
            scanf("%d",&n);
            equ = var = n*n ;
            rep0(i,0,var){
                char c = getchar();
                if(c == 'w') a[i][var] = 1;
                else if(c == 'y') a[i][var] = 0;
                else i--;
            }
            init(n);
            int ret = Guass();
            if(ret == -1) puts("inf");
            else printf("%d
    ",ret);
        }
        return 0;
    }
    View Code
  • 相关阅读:
    nullnullUVa 10066 The Twin Towers(LCS水题)
    代码错误zoj1298Domino Effect
    实现图形Qt学习:三维绘图之OpenGL和Qt的结合
    情况数组zoj2412Farm Irrigation
    nullnulle人事管理系统人事档案变更管理人员合同变更
    判断条件UVa 10192 Vacation(LCS水题)
    查询数量查看表的所有相关列信息
    代码提交省赛啊省赛
    输入声音如何搜索一张发音的图片
    数组字符串uva 10405 Longest Common Subsequence(最长公共子序列)
  • 原文地址:https://www.cnblogs.com/hxer/p/5181751.html
Copyright © 2011-2022 走看看