写的好累啊,还没有AC,应该是卡精度了,悲剧,再想想吧。
Wrong Answer
#include <iostream> #include <stdio.h> #include <string.h> #include <math.h> using namespace std; #define zero(x) ((x>0? x:-x)<1e-15) int const MAXN = 1010; double a[MAXN][MAXN]; double b[MAXN][MAXN]; int g[505][505]; int n,m; double R; struct Edge{ double r,k; }edge[505][505]; struct Node{ double x,y; }node[505]; double dis(double x1,double y1,double x2,double y2){ return sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2)); } double krc(double x1,double y1,double x2,double y2){ if((x1-x2)==0) return 540000.0; else return (y1-y2)/(x1-x2); } bool is_bet(int i,int z,int j){ if(node[i].x<=node[j].x && node[i].y <= node[j].y && node[i].x<=node[z].x && node[z].x<=node[j].x && node[i].y<=node[z].y && node[z].y<=node[j].y) return 1; else if(node[i].x>=node[j].x && node[i].y <= node[j].y && node[i].x>=node[z].x && node[z].x>=node[j].x && node[i].y<=node[z].y && node[z].y<=node[j].y) return 1; else if(node[i].x<=node[j].x && node[i].y >= node[j].y && node[i].x<=node[z].x && node[z].x<=node[j].x && node[i].y>=node[z].y && node[z].y>=node[j].y) return 1; else if(node[i].x>=node[j].x && node[i].y >= node[j].y && node[i].x>=node[z].x && node[z].x>=node[j].x && node[i].y>=node[z].y && node[z].y>=node[j].y) return 1; else return 0; } bool judge_bet(int i,int j){ for(int z=i+1;z<n;z++){ if(edge[i][z].k==edge[i][j].k && edge[i][z].r<edge[i][j].r && is_bet(i,z,j)){ return 1; } } return 0; } double det(double a[MAXN][MAXN],int n) { int i, j, k, sign = 0; double ret = 1, t; for (i = 0; i < n; i++) for (j = 0; j < n; j++) b[i][j] = a[i][j]; for (i = 0; i < n; i++) { if (zero(b[i][i])) { for (j = i + 1; j < n; j++) if (!zero(b[j][i])) break; if (j == n) return 0; for (k = i; k < n; k++) t = b[i][k], b[i][k] = b[j][k], b[j][k] = t; sign++; } ret *= b[i][i]; for (k = i + 1; k < n; k++) b[i][k] /= b[i][i]; for (j = i + 1; j < n; j++) for (k = i + 1; k < n; k++) b[j][k] -= b[j][i] * b[i][k]; } if (sign & 1) ret = -ret; return ret; } void build(){ memset(g,0,sizeof(g)); for(int i=0;i<n;i++){ for(int j=0;j<n;j++){ edge[i][j].r=dis(node[i].x,node[i].y,node[j].x,node[j].y); edge[i][j].k=krc(node[i].x,node[i].y,node[j].x,node[j].y); } edge[i][i].r=0; edge[i][i].k=0; } for(int i=0;i<n;i++){ for(int j=i+1;j<n;j++){ if(edge[i][j].r<=R && !judge_bet(i,j)){ g[i][j]=g[j][i]=1; } } } } void solve(){ memset(a,0,sizeof(a)); for (int i=0;i<n;i++) { int d=0; for (int j=0;j<n;j++) if (g[i][j]) d++; a[i][i]=d; } for (int i=0;i<n;i++) for (int j=0;j<n;j++) if (g[i][j]) a[i][j]=-1; } bool judge(){ for(int i=0;i<n;i++){ int flag=0; for(int j=0;j<n;j++){ if(g[i][j]!=0) flag=1; } if(!flag) return 1; } return 0; } int main() { //freopen("in.txt","r",stdin); int ncas; double x,y; cin >> ncas; while(ncas--){ scanf("%d%lf",&n,&R); for(int i=0;i<n;i++){ scanf("%lf%lf",&x,&y); node[i].x=x; node[i].y=y; } build(); if(judge()){ printf("-1\n"); continue; } solve(); double ans=det(a,n-1); printf("%0.0lf\n",ans+0.001); } return 0; }
终于AC了,原来是忘了MOD的问题了.
注意一下解行列式的过程,由于结果非常大,所以需要mod一个10007.在做除法的时候要改为乘以其逆元。
一定要注意求逆元的那些数必须为正数(即代表度数矩阵的位置)。
b[j][k] =((b[j][k]- b[j][i] * b[i][k]))%MOD;
if(j==k) b[j][k]=(b[j][k]+MOD)%MOD;
如果WA在这里,是因为本以为只要保证最后的结果为正数就可以了,中间高斯消元严格按照过程来就可以了。事实上是不对的。
问题出在扩展欧几里得算法上。
举一个例子。当我们想知道 -1*x=1(mod 7)的时候,如果用exgcd(-1,7,x,y)求出来的x其实是1,而不是我们所期望的6!! 为什么?扩展欧几里得此时求出来的值并不是最大公约数1,而是-1!计算的是-1*x=-1(mod 7)!!所以我们应当将1转为6才能得到正确答案。
还有一个需要注意的地方是任意交换行列式的两行,行列式计算出来的结果需要乘以-1,这个非常容易证明。而我们需要求的是基尔霍夫行列式的绝对值,因此需要记录一下消元过程中行列式交换的次数,如果是奇数,所得到的ans应该为mod-ans.
RANK-1,实在是个惊喜,也许这就是我最好的生日礼物.
附AC代码:
Accepted
#include <iostream> #include <stdio.h> #include <string.h> #include <math.h> using namespace std; #define MOD 10007 #define zero(x) ((x>0? x:-x)<1e-15) int const MAXN = 1010; int a[MAXN][MAXN]; int b[MAXN][MAXN]; int g[505][505]; int n,m; double R; struct Edge{ double r,k; }edge[505][505]; struct Node{ double x,y; }node[505]; double dis(double x1,double y1,double x2,double y2){ return sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2)); } double krc(double x1,double y1,double x2,double y2){ if((x1-x2)==0) return 540000.0; else return (y1-y2)/(x1-x2); } int exgcd(int a,int b,int &x,int &y) { if (b==0) { x=1;y=0;return a; } int d=exgcd(b,a%b,x,y); int t=x;x=y;y=t-a/b*y; return d; } bool is_bet(int i,int z,int j){ if(node[i].x<=node[j].x && node[i].y <= node[j].y && node[i].x<=node[z].x && node[z].x<=node[j].x && node[i].y<=node[z].y && node[z].y<=node[j].y) return 1; else if(node[i].x>=node[j].x && node[i].y <= node[j].y && node[i].x>=node[z].x && node[z].x>=node[j].x && node[i].y<=node[z].y && node[z].y<=node[j].y) return 1; else if(node[i].x<=node[j].x && node[i].y >= node[j].y && node[i].x<=node[z].x && node[z].x<=node[j].x && node[i].y>=node[z].y && node[z].y>=node[j].y) return 1; else if(node[i].x>=node[j].x && node[i].y >= node[j].y && node[i].x>=node[z].x && node[z].x>=node[j].x && node[i].y>=node[z].y && node[z].y>=node[j].y) return 1; else return 0; } bool judge_bet(int i,int j){ for(int z=i+1;z<n;z++){ if(edge[i][z].k==edge[i][j].k && edge[i][z].r<edge[i][j].r && is_bet(i,z,j)){ return 1; } } return 0; } int det(int a[MAXN][MAXN],int n) { int i, j, k, sign = 0; int ret = 1, t; for (i = 0; i < n; i++) for (j = 0; j < n; j++) b[i][j] = a[i][j]; for (i = 0; i < n; i++) { if (zero(b[i][i])) { for (j = i + 1; j < n; j++) if (!zero(b[j][i])) break; if (j == n) return 0; for (k = i; k < n; k++) t = b[i][k], b[i][k] = b[j][k], b[j][k] = t; sign++; } ret = ret*b[i][i]%MOD; int x,y; int tp=exgcd(b[i][i],MOD,x,y); for (k = i + 1; k < n; k++) b[i][k] =b[i][k]*x%MOD; for (j = i + 1; j < n; j++) for (k = i + 1; k < n; k++){ b[j][k] =((b[j][k]- b[j][i] * b[i][k]))%MOD; if(j==k) b[j][k]=(b[j][k]+MOD)%MOD; } } ret=(ret%MOD+MOD)%MOD; if (sign & 1) return MOD-ret; return ret; } void build(){ memset(g,0,sizeof(g)); for(int i=0;i<n;i++){ for(int j=0;j<n;j++){ edge[i][j].r=dis(node[i].x,node[i].y,node[j].x,node[j].y); edge[i][j].k=krc(node[i].x,node[i].y,node[j].x,node[j].y); } edge[i][i].r=0; edge[i][i].k=0; } for(int i=0;i<n;i++){ for(int j=i+1;j<n;j++){ if(edge[i][j].r<=R && !judge_bet(i,j)){ g[i][j]=g[j][i]=1; } } } } void solve(){ memset(a,0,sizeof(a)); for (int i=0;i<n;i++) { int d=0; for (int j=0;j<n;j++) if (g[i][j]) d++; a[i][i]=d; } for (int i=0;i<n;i++) for (int j=0;j<n;j++) if (g[i][j]) a[i][j]=-1; } bool judge(){ for(int i=0;i<n;i++){ int flag=0; for(int j=0;j<n;j++){ if(g[i][j]!=0) flag=1; } if(!flag) return 1; } return 0; } int main() { //freopen("in.txt","r",stdin); int ncas; double x,y; cin >> ncas; while(ncas--){ scanf("%d%lf",&n,&R); for(int i=0;i<n;i++){ scanf("%lf%lf",&x,&y); node[i].x=x; node[i].y=y; } build(); if(judge()){ printf("-1\n"); continue; } solve(); int ans=det(a,n-1); printf("%d\n",ans); } return 0; }