BZOJ1077 并查集
1077: [SCOI2008]天平
Time Limit: 10 Sec Memory Limit: 162 MBSubmit: 416 Solved: 224
[Submit][Status][Discuss]
Description
你有n个砝码,均为1克,2克或者3克。你并不清楚每个砝码的重量,但你知道其中一些砝码重量的大小关系。
你把其中两个砝码A和B放在天平的左边,需要另外选出两个砝码放在天平的右边。问:有多少种选法使得天平的左
边重(c1)、一样重(c2)、右边重(c3)?(只有结果保证惟一的选法才统计在内)
Input
第一行包含三个正整数n,A,B(1<=A,B<=N,A和B不相等)。砝码编号为1~N。以下n行包含重量关系矩阵,
其中第i行第j个字符为加号“+”表示砝码i比砝码j重,减号“-”表示砝码i比砝码j轻,等号“=”表示砝码i和砝
码j一样重,问号“?”表示二者的关系未知。存在一种情况符合该矩阵
Output
仅一行,包含三个整数,即c1,c2和c3。
Sample Input
6 2 5
?+????
-?+???
?-????
????+?
???-?+
????-?
?+????
-?+???
?-????
????+?
???-?+
????-?
Sample Output
1 4 1
HINT
【数据规模】 4<=n<=50
http://blog.csdn.net/wxh010910/article/details/56012133
#include<cstdio>
#include<cstring>
using namespace std;
const int N=52;
int fa[N],l[N],r[N],g[N][N],v[N];
int ans1,ans2,ans3;
int n,A,B;
int q[N],top;
char ch[N][N];
inline int findx(int x){return x==fa[x]?fa[x]:fa[x]=findx(fa[x]);}
inline void uni(int x,int y){fa[findx(x)]=findx(y);}
inline int sgn(int x){return !x?0:(x>0?1:-1);}
int main(){
scanf("%d%d%d",&n,&A,&B);
for(int i=1;i<=n;++i) fa[i]=i;
for(int i=1;i<=n;++i){
scanf("%s",ch[i]+1);
for(int j=1;j<=n;++j) if(ch[i][j]=='=') uni(i,j);
}
for(int i=1;i<=n;++i)
for(int j=1;j<=n;++j)
if(ch[i][j]=='+') g[findx(i)][findx(j)]=1;
else if(ch[i][j]=='-') g[findx(i)][findx(j)]=-1;
for(int i=1;i<=n;++i) if(findx(i)==i) q[++top]=i;
for(int i=1;i<=top;++i){
bool L=0,R=0;
for(int j=1;j<=top;++j) L|=(g[q[i]][q[j]]==1),R|=(g[q[i]][q[j]]==-1);
if(!L||!R) continue;
v[q[i]]=2;
for(int j=1;j<=top;++j)
if(g[q[i]][q[j]]==1) v[q[j]]=1;
else if(g[q[i]][q[j]]==-1) v[q[j]]=3;
}
for(int i=1;i<=top;++i){
l[q[i]]=1,r[q[i]]=3;
if(v[q[i]]) l[q[i]]=r[q[i]]=v[q[i]];
else for(int j=1;j<=top;++j)
if(g[q[i]][q[j]]==1) l[q[i]]=2;
else if(g[q[i]][q[j]]==-1) r[q[i]]=2;
}
for(int i=1;i<n;++i) if(i!=A&&i!=B)
for(int j=i+1;j<=n;++j) if(j!=A&&j!=B)
{
int fi=findx(i),fj=findx(j),fa=findx(A),fb=findx(B);
int t1=0,t2=0,t3=0;
for(int vi=l[fi];vi<=r[fi];++vi) for(int vj=l[fj];vj<=r[fj];++vj)
for(int va=l[fa];va<=r[fa];++va) for(int vb=l[fb];vb<=r[fb];++vb)
{
int F[4]={fi,fj,fa,fb},V[4]={vi,vj,va,vb};
bool flag=1;
for(int x=0;x<4;++x) for(int y=0;y<4;++y)
if(F[x]==F[y]&&V[x]!=V[y]) {flag=false;break;}
for(int x=0;x<4;++x) for(int y=0;y<4;++y)
if(g[F[x]][F[y]]&&sgn(V[x]-V[y])!=g[F[x]][F[y]]) {flag=false;break;}
if( !flag ) continue;
if( va + vb > vi + vj ) t1 = 1;
if( va + vb == vi + vj ) t2 = 1;
if( va + vb < vi + vj ) t3 = 1;
}
if( t1 + t2 + t3 == 1 ) ans1 += t1, ans2 += t2, ans3 += t3;
}
printf("%d %d %d\n",ans1,ans2,ans3);
}
#include<cstring>
using namespace std;
const int N=52;
int fa[N],l[N],r[N],g[N][N],v[N];
int ans1,ans2,ans3;
int n,A,B;
int q[N],top;
char ch[N][N];
inline int findx(int x){return x==fa[x]?fa[x]:fa[x]=findx(fa[x]);}
inline void uni(int x,int y){fa[findx(x)]=findx(y);}
inline int sgn(int x){return !x?0:(x>0?1:-1);}
int main(){
scanf("%d%d%d",&n,&A,&B);
for(int i=1;i<=n;++i) fa[i]=i;
for(int i=1;i<=n;++i){
scanf("%s",ch[i]+1);
for(int j=1;j<=n;++j) if(ch[i][j]=='=') uni(i,j);
}
for(int i=1;i<=n;++i)
for(int j=1;j<=n;++j)
if(ch[i][j]=='+') g[findx(i)][findx(j)]=1;
else if(ch[i][j]=='-') g[findx(i)][findx(j)]=-1;
for(int i=1;i<=n;++i) if(findx(i)==i) q[++top]=i;
for(int i=1;i<=top;++i){
bool L=0,R=0;
for(int j=1;j<=top;++j) L|=(g[q[i]][q[j]]==1),R|=(g[q[i]][q[j]]==-1);
if(!L||!R) continue;
v[q[i]]=2;
for(int j=1;j<=top;++j)
if(g[q[i]][q[j]]==1) v[q[j]]=1;
else if(g[q[i]][q[j]]==-1) v[q[j]]=3;
}
for(int i=1;i<=top;++i){
l[q[i]]=1,r[q[i]]=3;
if(v[q[i]]) l[q[i]]=r[q[i]]=v[q[i]];
else for(int j=1;j<=top;++j)
if(g[q[i]][q[j]]==1) l[q[i]]=2;
else if(g[q[i]][q[j]]==-1) r[q[i]]=2;
}
for(int i=1;i<n;++i) if(i!=A&&i!=B)
for(int j=i+1;j<=n;++j) if(j!=A&&j!=B)
{
int fi=findx(i),fj=findx(j),fa=findx(A),fb=findx(B);
int t1=0,t2=0,t3=0;
for(int vi=l[fi];vi<=r[fi];++vi) for(int vj=l[fj];vj<=r[fj];++vj)
for(int va=l[fa];va<=r[fa];++va) for(int vb=l[fb];vb<=r[fb];++vb)
{
int F[4]={fi,fj,fa,fb},V[4]={vi,vj,va,vb};
bool flag=1;
for(int x=0;x<4;++x) for(int y=0;y<4;++y)
if(F[x]==F[y]&&V[x]!=V[y]) {flag=false;break;}
for(int x=0;x<4;++x) for(int y=0;y<4;++y)
if(g[F[x]][F[y]]&&sgn(V[x]-V[y])!=g[F[x]][F[y]]) {flag=false;break;}
if( !flag ) continue;
if( va + vb > vi + vj ) t1 = 1;
if( va + vb == vi + vj ) t2 = 1;
if( va + vb < vi + vj ) t3 = 1;
}
if( t1 + t2 + t3 == 1 ) ans1 += t1, ans2 += t2, ans3 += t3;
}
printf("%d %d %d\n",ans1,ans2,ans3);
}