bzoj2668 [BeiJing wc2012]连连看
赤果果的费用流,我闲的练单纯形的模板,不过发现跑的还挺快的...哈哈。
N^2预处理出一些需要用到的信息,然后变量是一个y^2-x^2=z^2的等式,每个约束条件是一个数在每个等式中出现的次数和小于等于1,这样就很直观了。为了方便,可以把预处理是出现在等式中得数字离散出来,构造出矩阵就行了。
单纯形最麻烦的就是构造矩阵了,算法的操作实际上就是个类似高斯消元的东西,由于是0-1单纯形,这种写法就挺舒服的了。
对于方案数,直接求出各个等式变量的值就行了,具体方法是看哪个等式的MAT[i][0]=0.
Match
1 #include<iostream> 2 #include<cstdio> 3 #include<algorithm> 4 #include<cmath> 5 #include<cstring> 6 #define maxn 1010 7 #define inf 2147483647 8 using namespace std; 9 int mat[1000][1000],num[1000][1000],next[maxn],c[maxn],rank[maxn]; 10 bool v[maxn*maxn],p[maxn][maxn],ls[maxn]; 11 int n,m,a,b,sum; 12 13 void change(int x,int e) 14 { 15 int last=-1; 16 for (int i=0;i<=m;i++) 17 if (mat[x][i]) 18 { 19 next[i]=last; 20 last=i; 21 } 22 for (int i=0;i<=n;i++) 23 { 24 if (i==x||mat[i][e]==0) continue; 25 for (int j=last;j!=-1;j=next[j]) 26 { 27 if (j==e) continue; 28 mat[i][j]-=mat[i][e]*mat[x][j]; 29 } 30 mat[i][e]=-mat[i][e]; 31 } 32 } 33 34 int simplex() 35 { 36 while (1) 37 { 38 int now=0; 39 for (int i=1;i<=m;i++) 40 if (mat[0][i]>0) { 41 now=i; 42 break; 43 } 44 if (now==0) return -mat[0][0]; 45 int tmp,mi=inf; 46 for (int i=1;i<=n;i++) 47 if (mat[i][now]>0&&mat[i][0]<mi) 48 mi=mat[i][0],tmp=i; 49 change(tmp,now); 50 } 51 } 52 53 int gcd(int a,int b) 54 { 55 if (b==0) return a; 56 else return gcd(b,a%b); 57 } 58 59 int main() 60 { 61 scanf("%d%d",&a,&b); 62 for (int i=1;i<=b;i++) v[i*i]=1; 63 memset(ls,0,sizeof(ls)); 64 for (int i=a;i<=b;i++) 65 for (int j=a;j<i;j++) 66 if (v[i*i-j*j]&&gcd(i,j)==1) 67 { 68 p[i][j]=1; 69 if (!ls[i]) c[++n]=i,ls[i]=1; 70 if (!ls[j]) c[++n]=j,ls[j]=1; 71 } 72 sort(c+1,c+n+1); 73 for (int i=1;i<=n;i++) rank[c[i]]=i; 74 for (int i=a;i<=b;i++) 75 for (int j=a;j<i;j++) 76 { 77 if (p[i][j]) 78 { 79 m++; 80 mat[rank[i]][m]=1; 81 mat[rank[j]][m]=1; 82 mat[0][m]=i+j; 83 } 84 } 85 for (int i=1;i<=n;i++) 86 mat[i][0]=1; 87 int ans=simplex(); 88 for (int i=1;i<=n;i++) sum+=(mat[i][0]==0); 89 printf("%d %d\n",sum,ans); 90 return 0; 91 }
AC without art, no better than WA !