51nod 1318 最大公约数与最小公倍数方程组 2-SAT+数学
来源:互联网 发布:sat 句子合并 知乎 编辑:程序博客网 时间:2024/06/15 17:47
题意
求解一个有趣的方程组,方程组有N个未知正整数,x[0],x[1],x[2],…,x[N-1]。
方程组由M个方程组成,方程只有两种类型:
1)GCD(x[i],x[j]) = G ;其中,i != j,且GCD(a,b)为正整数a与b的最大公约数的值
2)LCM(x[i],x[j]) = L ;其中,i != j,且LCM(c,d)为正整数c与d的最小公倍数的值
你需要判断这样一个方程组是否存在解,且N个未知数都是正整数。
问题包含多组测试数据。
输入数据的第一行是一个整数T,表示有T组测试数据,1<=T<=10.
之后有T组相同结构的数据。
每组数据的第一行有两个整数N、M,分别表示未知数个数与方程个数,其中1<=N<=200,1<=M<=200.
之后M行,每行表示一个方程。
第i个方程格式为:”ti ai bi ci”,其中,ti为一个字符,ai,bi为[0,N-1]上的整数,1<=ci<=1,000,000,000。
如果ti=’L’,表示该方程为 LCM(x[ai],x[bi])=ci;
如果ti=’G’,表示该方程为 GCD(x[ai],x[bi])=ci。
分析
这题是真的难打。。。
思路其实并不难。我们对每一种素数分开处理。设当前处理到素数p,p在x中的指数为p1,在y中的指数为p2,LCM(x,y)则表示max(p1,p2)=c,GCD(x,y)则表示min(p1,p2)=c。
可以把每个变量拆成k个点对,其中的第i个点对(xi,yi),xi表示该变量选p^i,yi则表示不选。2-SAT建图之后跑一下即可。
代码
#include<iostream>#include<cstdio>#include<cstdlib>#include<cstring>#include<algorithm>using namespace std;const int N=205;int n,m,zhi,tot,tot_block,dfn[N*N],low[N*N],stack[N*N],top,bel[N*N],last[N*N],prime[N*N],tim,cnt,mx;bool del[N*N],ins[N*N],val[N*N],vis[N*N];struct edge{int to,next;}e[N*N*N];struct data{int op,a,b,c;}pro[N];int read(){ int x=0,f=1;char ch=getchar(); while (ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} while (ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();} return x*f;}void divi(int n){ for (int i=2;i*i<=n;i++) if (n%i==0) { prime[++tot]=i; while (n%i==0) n/=i; } if (n>1) prime[++tot]=n;}int point(int x,int y,int z){ return ((x-1)*(zhi+1)+y+1)*2-z;}void addedge(int u,int v){ //if (del[u]||del[v]) return; e[++cnt].to=v;e[cnt].next=last[u];last[u]=cnt;}void tarjan(int x){ dfn[x]=low[x]=++tim; stack[++top]=x;ins[x]=1; for (int i=last[x];i;i=e[i].next) if (!dfn[e[i].to]&&!del[e[i].to]) tarjan(e[i].to),low[x]=min(low[x],low[e[i].to]); else if (ins[e[i].to]&&!del[e[i].to]) low[x]=min(low[x],dfn[e[i].to]); if (dfn[x]==low[x]) { tot_block++;int y; while (y!=x) { y=stack[top];top--; ins[y]=0;bel[y]=tot_block; } }}bool check(int pri){ zhi=0;int tmp=mx; while (tmp>=pri) zhi++,tmp/=pri; int s=point(n,zhi,0); for (int i=1;i<=s;i++) last[i]=del[i]=dfn[i]=low[i]=0;cnt=tim=tot_block=0; for (int i=1;i<=n;i++) for (int j=0;j<=zhi;j++) for (int k=0;k<=zhi;k++) if (j!=k) addedge(point(i,j,1),point(i,k,0)); for (int i=1;i<=m;i++) { int x=pro[i].a,y=pro[i].b,z=0,tmp=pro[i].c; while (tmp%pri==0) tmp/=pri,z++; if (del[point(x,z,0)]&&del[point(y,z,0)]) return 0; if (!pro[i].op) { for (int j=0;j<z;j++) del[point(x,j,0)]=del[point(x,j,1)]=del[point(y,j,0)]=del[point(y,j,1)]=1; for (int j=z+1;j<=zhi;j++) addedge(point(x,j,1),point(y,z,1)),addedge(point(y,j,1),point(x,z,1)); } else { for (int j=z+1;j<=zhi;j++) del[point(x,j,0)]=del[point(x,j,1)]=del[point(y,j,0)]=del[point(y,j,1)]=1; for (int j=0;j<z;j++) addedge(point(x,j,1),point(y,z,1)),addedge(point(y,j,1),point(x,z,1)); } } for (int i=1;i<=s;i++) if (!dfn[i]&&!del[i]) tarjan(i); for (int i=1;i<=tot_block;i++) val[i]=0; for (int i=1;i<=s;i++) if (!del[i]) for (int j=last[i];j;j=e[j].next) if (del[e[j].to]&&(e[j].to&1)) {val[bel[i]]=1;break;} for (int i=1;i<=n;i++) { for (int j=0;j<=zhi;j++) { if (del[point(i,j,1)]) continue; if (bel[point(i,j,1)]==bel[point(i,j,0)]) val[bel[point(i,j,0)]]=1; if (vis[bel[point(i,j,1)]]) val[bel[point(i,j,1)]]=1; else vis[bel[point(i,j,1)]]=1; } for (int j=0;j<=zhi;j++) vis[bel[point(i,j,1)]]=0; } for (int i=1;i<=n;i++) { int flag=0; for (int j=0;j<=zhi;j++) { if (del[point(i,j,0)]||val[bel[point(i,j,1)]]) continue; flag=1;break; } if (!flag) return 0; } return 1;}int main(){ int T=read(); while (T--) { n=read();m=read();mx=0; for (int i=1;i<=m;i++) { char ch[2];scanf("%s",ch); pro[i].a=read()+1;pro[i].b=read()+1;pro[i].op=ch[0]=='G'?0:1; divi(pro[i].c=read());mx=max(mx,pro[i].c); } sort(prime+1,prime+tot+1);tot=unique(prime+1,prime+tot+1)-prime-1; int flag=0; for (int i=1;i<=tot;i++) if (!check(prime[i])) {flag=1;break;} if (!flag) puts("Solution exists"); else puts("Solution does not exist"); } return 0;}
阅读全文
0 0
- 51nod 1318 最大公约数与最小公倍数方程组 2-SAT+数学
- 51nod 1318 最大公约数与最小公倍数方程组
- 51nod 最大公约数 & 最小公倍数
- 51 nod 最大公约数的最小公倍数
- 数学 HDU 2504、2028 最大公约数 与 最小公倍数
- 51nod 1419 最小公倍数挑战(数学)
- 51nod 1040 最大公约数之和 (数学)
- HDU 1713 相遇周期(数学 最大公约数与最小公倍数)
- 【数学基础】【最小公倍数和最大公约数】
- 求最大公约数与最小公倍数
- 最大公约数与最小公倍数问题
- 求最大公约数与最小公倍数
- 最大公约数与最小公倍数
- 最大公约数与最小公倍数
- 求最大公约数与最小公倍数
- 最大公约数 与 最小公倍数
- 最大公约数与最小公倍数源码
- 最小公倍数与最大公约数
- JAVA删除字符串中指定字符集(删除敏感字符)
- iOS App的整个生命周期
- c++中string类的基本实现
- CodeForces 26 C.Parquet(构造)
- 做百度知道营销不可忽视的问题
- 51nod 1318 最大公约数与最小公倍数方程组 2-SAT+数学
- Android NDK开发扫盲及最新CMake的编译使用
- 单片机实验四
- error setting properties values
- SQL反模式(五)
- OllyDbg 官网及下载地址
- Python:ndscheduler
- [收藏] solr 5.5 设置访问密码
- 学习RSS