Spanning trees in a secure lock pattern UVALive

来源:互联网 发布:中国的穆斯林问题 知乎 编辑:程序博客网 时间:2024/06/05 08:54
题意:如果仔细看了题的话,其实就是求一个行列式去掉第i行第i列的值,
     题面提示了随便去掉哪i行i列结果都是相同的
 
思路:行列式的定义 见 线性代数
     求行列式的值 用到了高斯消元的模板,有关资料 见算法竞赛入门经典训练之南 151~155页
     首先根据题意构造好矩阵
     如果i = j 则a[i][j]等于i的度数
     否则 如果i , j间有边 a[i][j] = 1,否则为-1

     高斯消元之后 变成一个上三角矩阵 ,答案就是对角线上值的乘积

#include <iostream>#include <cstdio>#include <cstdlib>#include <cstring>#include <algorithm>#include <vector>#include <map>#include <cmath>#include <set>#include <queue>using namespace std;typedef long long ll;const int INF=1e9+10;const double EPS = 1e-10;  const ll mod=1e9+7;typedef pair<int,int> P;const int maxn=100;typedef double Matrix[maxn][maxn];Matrix A;void gauss_elimination(int n){//A为增广矩阵,A[i][n]是第i个未知数的值//消元过程for(int i=0;i<n;i++){//选一行r并与第i行交换, 选择最大的那个,列主元消元法int r=i;for(int j=i+1;j<n;j++)if(fabs(A[j][i])>fabs(A[r][i])) r=j;if(r!=i) for(int j=0;j<=n;j++) swap(A[r][j],A[i][j]);//换行时   ans应*-1,不过不乘在本题中也没有关系//与第i+1~n行进行消元for(int k=i+1;k<n;k++){double f=A[k][i]/A[i][i];//为了让A[k][i]=0,第i行所乘的倍数for(int j=i;j<=n;j++) A[k][j]-=f*A[i][j];}}//回代过程/*for(int i=n-1;i>=0;i--){for(int j=i+1;j<n;j++)A[i][n]-=A[j][n]*A[i][j];A[i][n]/=A[i][i];}*/}int n;const int dx[]={-1,-1,-1,1,1,1,0,0};const int dy[]={1,-1,0,1,-1,0,-1,1};void work(int x,int y,int id){int ans=0;for(int i=0;i<8;i++){int xx=x+dx[i],yy=y+dy[i];if(xx<0||xx>=n||yy<0||yy>=n) continue;ans++;}A[id][id]=ans;}bool judge(int x1,int y1,int x2,int y2){for(int i=0;i<8;i++){int xx=x1+dx[i],yy=y1+dy[i];if(xx<0||xx>=n||yy<0||yy>=n) continue;if(xx==x2&&yy==y2) return true;}return false;}int main(){//freopen("out.txt","w",stdout);//ios_base::sync_with_stdio(0);int t;scanf("%d",&t);while(t--){scanf("%d",&n);for(int i=0;i<n*n;i++){for(int j=0;j<n*n;j++){if(i==j) work(i/n,i%n,i);else{if(judge(i/n,i%n,j/n,j%n))A[i][j]=-1;elseA[i][j]=0;}}}gauss_elimination(n*n-1);double ans=1.0;for(int i=0;i<n*n-1;i++)ans*=A[i][i];printf("%.0f\n",ans );}    return 0;}


原创粉丝点击