P3005 [USACO10DEC]槽的游戏 [搜索]

槽的游戏

题目描述见链接 .


color{grey}{最初想法}

直接上 高斯消元, 发现只能得到 70pts70pts,

代码,

#include<bits/stdc++.h>
#define reg register

const double eps = 1e-12;

int read(){
        char c;
        int s = 0, flag = 1;
        while((c=getchar()) && !isdigit(c))
                if(c == '-'){ flag = -1, c = getchar(); break ; }
        while(isdigit(c)) s = s*10 + c-'0', c = getchar();
        return s * flag;
}

const int maxn = 105;

int N;
int M;

double A[maxn][maxn];

char Tmp[25];

int Fuck(){

        int t = 1;
        for(reg int i = 1; i <= M && t <= N; i ++, t ++){
                int max_id = t;
                for(reg int j = t+1; j <= M; j ++) if(A[j][i] > A[max_id][i]) max_id = j;
                if(!A[max_id][i]){ t --; continue ; }
                std::swap(A[max_id], A[t]);
                for(reg int j = N+1; j >= i; j --) A[t][j] /= A[t][i];
                if(A[t][i] < 0) for(reg int j = 1; j <= N+1; j ++) A[t][j] = -A[t][j];
                for(reg int j = t+1; j <= M; j ++){
                        if(!A[j][i]) continue ;
                        for(reg int k = N+1; k >= i; k --) A[j][k] -= A[j][i] * A[t][k];
                }
        }
        t --;
        for(reg int i = t; i >= 1; i --)
                for(reg int j = i+1; j <= N; j ++) A[i][N+1] -= A[j][N+1]*A[i][j], A[i][j] = 0;
        for(reg int i = t+1; i <= N; i ++) if(fabs(A[i][N+1]) > eps) return -1;
        if(t < N) return 0;
        return 1;
}

int main(){
        N = read(), M = read();
        for(reg int i = 1; i <= M; i ++){
                scanf("%s", Tmp+1);
                for(reg int j = 1; j <= N; j ++) A[i][j] = Tmp[j] - '0';
                A[i][N+1] = read();
        }
        int flag = Fuck();
        if(flag == -1) printf("IMPOSSIBLE
");
        else if(flag == 0) printf("NOT UNIQUE
");
        else for(reg int i = 1; i <= N; i ++) printf("%.0lf", fabs(A[i][N+1]));
        return 0;
}

原来是因为当方程的个数小于 NN 个, 且仅有一种合法方案使得方程组成立时, 高斯消元 是判其多解的 .

例如这组数据:

5 1
11111 5

color{red}{正解部分}

直接将每个方程化为二进制形式, 暴力搜索, 搜索 时剪剪枝就可以 AcAc 了 …


color{red}{实现部分}

#include<bits/stdc++.h>
#define reg register

const int maxn = 105;

int N;
int M;
int flag;
int flag_2;
int ans[maxn];
int res[maxn];

char Smp[22];

struct Node{ int max_bit, zt, val; } A[maxn];

bool cmp(Node a, Node b){ return a.max_bit < b.max_bit; }

bool check(const int &lev){
        for(reg int i = 1; i <= M; i ++){
                if(A[i].max_bit > lev) break ;
                int s = 0;
                for(reg int j = 1; j <= N; j ++) if(A[i].zt & (1<<j-1)) s += ans[j];
                if(s != A[i].val) return 0;
        }
        return 1;
}

void DFS(int k, int zt){
        if(flag_2) return ;
        if(k == N+1){
                if(check(k+1)){
                        if(flag){ flag_2 = 1; return ; }
                        flag = 1;
                        for(reg int i = 1; i <= N; i ++) res[i] = ans[i];
                }
                return ;
        }
        ans[k] = 1;
        if(check(k)) DFS(k+1, zt|(1<<k-1));
        ans[k] = 0; DFS(k+1, zt);
}

int main(){
        scanf("%d%d", &N, &M);
        for(reg int i = 1; i <= M; i ++){
                scanf("%s", Smp+1);
                for(reg int j = 1; j <= N; j ++){
                        A[i].zt |= ((Smp[j]-'0') << (j-1));
                        if(Smp[j] == '1') A[i].max_bit = j;
                }
                scanf("%d", &A[i].val);
        }
        std::sort(A+1, A+M+1, cmp);
        DFS(1, 0);
        if(!flag) printf("IMPOSSIBLE
");
        else if(flag_2) printf("NOT UNIQUE
");
        else for(reg int i = 1; i <= N; i ++) printf("%d", res[i]);
        return 0;
}
原文地址:https://www.cnblogs.com/zbr162/p/11822433.html